项目github地址:bitcarmanlee easy-algorithm-interview-and-practice
欢迎大家star,留言,一起学习进步
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。