过河问题详解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/bitcarmanlee/article/details/89283694

1.问题描述

在漆黑的夜里,N位旅行者来到了一座狭窄而且没有护栏的桥边。如果不借助手电筒的话,大家是无论如何也不敢过桥去的。不幸的是,N个人一共只带了一只手电筒,而桥窄得只够让两个人同时过。如果各自单独过桥的话,N人所需要的时间已知;而如果两人同时过桥,所需要的时间就是走得比较慢的那个人单独行动时所需的时间。问题是,如何设计一个方案,让这N人尽快过桥。

或许还有类似的问题,问题的描述可能不尽完全相同,但是大致的思路是一致的。

2.解法

对于一个规模比较大的问题,我们或许可以从小问题开始尝试来解决。
假设N个人过桥所需要的时间保存在一个数组nums中,nums经过排序由小到大,即过桥时间由快到慢,假设时间分别为abcdefg,a<b<c<d<e<f<g。
N=1时,过桥的时间为a
N=2时,过桥所有的时间为b
N=3时,过桥所需要的时间为a+b+c(ab先过去,所需时间为b,a再回来,所需时间为a,然后ac在过去,所需时间为c)
N=4时,此时两种方案有:
方案1:让a带最慢d先过去,然后a回来,再带次慢的c过去,a再回来,最后ab一起过去。
此方案所需要的时间为d+a+c+a+b=2a+b+c+d
方案2:先让最快的两个人ab过去,然后a回来,再让最慢的两个人过去,b回来,最后ab一起过去。此方案所需要的时间为b+a+d+b+b=a+3b+d
具体采取哪种方案,只需要比较方案1与方案2哪个更小即可。

3.代码实现

import java.util.Arrays;
import java.util.Scanner;

/**
 * Created by wanglei on 19/4/13.
 */
public class CrossRiver {

    public static int time = 0;

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int[] nums = new int[n];
        for (int j = 0; j < n; j++) {
            nums[j] = in.nextInt();
        }
        Arrays.sort(nums);
        cross(nums);
        System.out.println("time is: " + time);
    }

    // method1: ad过去(d), a回来(a),ac过去(c),a回来(a), ab过去(b) all time: 2a+b+c+d
    // method2: ab过去(b), a回来(a), cd过去(d),b回来(b),ab过去(b) all time: a+3b+d
    public static void cross(int[] nums) {
        if (nums.length == 1) {
            time += nums[0];
            return;
        }
        if (nums.length == 2) {
            time += nums[1];
            return;
        }
        if (nums.length == 3) {
            time += nums[0] + nums[1] + nums[2];
            return;
        }
        if (nums.length > 3) {
            if (nums[0] + nums[nums.length - 2] < 2 * nums[1]) {
                time += 2 * nums[0] + nums[nums.length - 2] + nums[nums.length - 1];
            } else {
                time += nums[0] + 2 * nums[1] + nums[nums.length - 1];
            }
            int[] tmp = Arrays.copyOfRange(nums, 0, nums.length - 2);
            cross(tmp);
        }
    }
}

假设输入的第一行为4,表示有4个人。第二行输入的为10 2 5 1,表示4个人过桥所需要的时间。最后的结果为17。

猜你喜欢

转载自blog.csdn.net/bitcarmanlee/article/details/89283694