过河(DP)

 

在一个夜黑风高的晚上,有n个小朋友在桥的这边,现在他们需要过桥,但是由于桥很窄,每次只允许不超过两人通过,他们只有一个手电筒,所以每次过桥后,需要有人把手电筒带回来,第i号小朋友过桥的时间为ai,两个人过桥的总时间为二者中时间长者。问所有小朋友过桥的总时间最短是多少。

输入格式

第一行输入一个整数n(1≤n≤1000),表示有n个小朋友。

第二行有n个整数ai,ai表示第i个小朋友过河需要的时间(0<ai≤1000)。

输出格式

输出一个整数表示所有小朋友过河所需要的时间。

样例输入

4
1 2 5 10

样例输出

17

 

先考虑贪心,如果每次都让花费时间最少的人去送手电的话,样例答案就应该是19,但是实际答案应该是17,故不能一直让花费时间最少的人去送手电。

样例的具体步骤是这样的:

第一步:1和2过去,花费时间2,然后1回来(花费时间1);

第二歩:3和4过去,花费时间10,然后2回来(花费时间2);

第三步:1和2过去,花费时间2,总耗时17。

 

我们先将所有人按花费时间递增进行排序,假设前i个人过河花费的最少时间为dp[i]。

那么考虑前i-1个人过河的情况,即河这边还有1个人,河那边有i-1个人,并且这时候手电筒肯定在对岸,所以dp[i] = dp[i-1] + a[1] + a[i] (让花费时间最少的人把手电筒送过来,然后和第i个人一起过河)

如果河这边还有两个人,一个是第i号,另外一个无所谓,河那边有i-2个人,并且手电筒肯定在对岸,所以dp[i] = dp[i-2] + a[1] + a[i] + 2*a[2] (让花费时间最少的人把电筒送过来,然后第i个人和另外一个人一起过河,由于花费时间最少的人在这边,所以下一次送手电筒过来的一定是花费次少的,送过来后花费最少的和花费次少的一起过河,解决问题)

所以 dp[i] = min{dp[i-1] + a[1] + a[i] , dp[i-2] + a[1] + a[i] + 2*a[2] }

 

 

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <iostream>
 4 #include <string>
 5 #include <math.h>
 6 #include <algorithm>
 7 #include <vector>
 8 #include <stack>
 9 #include <queue>
10 #include <set>
11 #include <map>
12 #include <sstream>
13 const int INF=0x3f3f3f3f;
14 typedef long long LL;
15 using namespace std;
16 
17 int a[1010];
18 int dp[1010];
19 
20 int main()
21 {
22     int n;
23     scanf("%d",&n);
24     for(int i=1;i<=n;i++)
25         scanf("%d",&a[i]);
26     sort(a+1,a+1+n);
27     dp[1]=a[1]; dp[2]=a[2];
28     for(int i=3;i<=n;i++)
29     {
30         dp[i]=min(dp[i-1]+a[1]+a[i],dp[i-2]+a[1]+a[i]+2*a[2]);
31     }
32     printf("%d\n",dp[n]);
33     return 0;
34 }

 

 

-

posted @ 2020-01-16 15:11  jiamian22  阅读(309)  评论(0编辑  收藏  举报