4个人在晚上过一座小桥,过桥时必须要用到手电筒,只有一枚手电筒,每次最多只可以有两人通过, 4个人的过桥速度分别为1分钟A、2分钟B、5分钟C、10分钟D,试问最少需要多长时间4人才可以全部通过小桥?
答案是17分钟
先让A,B过桥(2分钟),再让A返回(1分钟),然后C,D一起过桥(10分钟),B返回(2分钟),最后A,B一起过桥(2分钟)。
我们来想一下这个过桥问题的能减少时间的地方:
- 让过桥时间少的人来传递手电筒
- 让过桥时间相差最小的两个人一起过桥(两人过桥取两者时间最大值)
解决思路:
针对因素1,让过桥时间少的人先过桥,这样他们可以回来传递手电筒。
针对因素2,将每个人按过桥时间进行排序,每次过桥取相邻的两个人,此时过桥时间相差最小。
方案:
先对每个人按过桥时间进行排序,然后按过桥时间长短进行过桥。我们使用DP来解
-
确定状态:
dp[i]:代表前i个人过桥所用的时间 -
转移方程:
dp[i]=min(dp[i-2]+a[1]+a[i]+a[2]+a[2],dp[i-1]+a[1]+a[i]);
第一种:对岸有两个人,让1,2来接,先让1过去(a[1]),然后i-1和i 两人过桥(a[i]),2再来接1(a[2]),1和2一起过桥(a[2])。
第二种:对岸有一个人,让1来接,先让1过去(a[1]),然后1和i一起过桥回来(a[i])。
- 初始值和边界情况
只有一个人或两个人过桥,不能被转移方程推导出来
dp[1]=a[1];
dp[2]=a[2];
边界为人数即可,求多了也没用
- 计算顺序,从小到大
package Demo1;
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
int n=scanner.nextInt();
int a[]=new int[n+1];
for(int i=1;i<=n;i++){
a[i]=scanner.nextInt();
}
Arrays.sort(a);
if(n==1){
System.out.println(a[1]);
return;
}
if(n==2){
System.out.println(a[2]);
return;
}
int dp[]=new int[n+1];
dp[1]=a[1];
dp[2]=a[2];
for(int i=3;i<=n;i++){
dp[i]=Math.min(dp[i-2]+a[1]+a[i]+a[2]+a[2],dp[i-1]+a[1]+a[i]);
}
System.out.println(dp[n]);
}
}