四人过桥问题与扩展(DP,其实也可以看成贪心)

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. 让过桥时间相差最小的两个人一起过桥(两人过桥取两者时间最大值)

解决思路:

针对因素1,让过桥时间少的人先过桥,这样他们可以回来传递手电筒。
针对因素2,将每个人按过桥时间进行排序,每次过桥取相邻的两个人,此时过桥时间相差最小。

方案:
先对每个人按过桥时间进行排序,然后按过桥时间长短进行过桥。我们使用DP来解

  1. 确定状态:
    dp[i]:代表前i个人过桥所用的时间

  2. 转移方程:

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])。

  1. 初始值和边界情况
    只有一个人或两个人过桥,不能被转移方程推导出来
dp[1]=a[1];
dp[2]=a[2];

边界为人数即可,求多了也没用

  1. 计算顺序,从小到大
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]);
    }
}

猜你喜欢

转载自blog.csdn.net/xiaoshazheng/article/details/109120402