River Crossing
Description
Afandi is herding N sheep across the expanses of grassland when he finds himself blocked by a river. A single raft is available for transportation.
Afandi knows that he must ride on the raft for all crossings, but adding sheep to the raft makes it traverse the river more slowly.
When Afandi is on the raft alone, it can cross the river in M minutes When the i sheep are added, it takes Mi minutes longer to cross the river than with i-1 sheep (i.e., total M+M1 minutes with one sheep, M+M1+M2 with two, etc.).
Determine the minimum time it takes for Afandi to get all of the sheep across the river (including time returning to get more sheep).
Input
On the first line of the input is a single positive integer k, telling the number of test cases to follow. 1 ≤ k ≤ 5 Each case contains.
- Line 1: one space-separated integers: N and M (1 ≤ N ≤ 1000 , 1≤ M ≤ 500).
- Lines 2…N+1: Line i+1 contains a single integer: Mi (1 ≤ Mi ≤ 1000)
Output
For each test case, output a line with the minimum time it takes for Afandi to get all of the sheep across the river.
Sample Input 1
2
2 10
3
5
5 10
3
4
6
100
1
Sample Output 1
18
50
题目大意: 有n只羊要求你在最小时间代价下将n只羊运送至河对岸,运送所消耗的时间要求如下:
假设只有你在船上则渡河时间为M,
一次运送一只羊时渡河时间为M+M1,
一次运送两只羊时渡河时间为M+M1+M2,
一次运送三只羊时渡河时间为M+M1+M2+M3
…
一次运送i只羊渡河时间为M+M1+…+Mi。
思路:我们一步一步分析:
假设有一只羊需要运输,显然一次运输完即可。
假设有两只羊需要运输:
1、我们可以一次运两只。
2、也可以第一趟运一只第二趟运一只。
假设有三只羊:
1、我们可以一次运三只。
2、也可以第一趟运一只第二趟运两只。
3、还可以第一趟运两只第二趟运一只。
依次类推。。。。。。。。。。。
每次我们都将运输分为两个部分,则四只羊就是:
运一只运三只、运两只运两只、运三只运一只、运四只。
…
我们会发现当有两只羊时运输的最优情况可能来自于只有一只羊的情况,此时我们只要取两种运法的最优情况即可。
同样当有三只羊时运输的最优情况可能来自运输两只羊的情况,同样我们取三种情况的最优解。
可能有点模糊,但还是可以发现动态规划的影子。
我们假设数组dp[i]存放的是运输i只羊的最优解,则状态转移方程可以表示为:dp[ i ] = min(dp[i], dp[ i - j ] + sum[ j ] + 2 * m)。
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 1005
#define INF 0x3f3f3f3f
int dp[MAXN], sum[MAXN];
int main()
{
int t, m, n, i, j;
cin >> t;
while (t--) {
sum[0] = 0;
cin >> n >> m;
for (i = 1; i <= n; i++) {
cin >> sum[i];
sum[i] += sum[i - 1];//使用前缀和表示运送i只所需要的时间
}
for (i = 1; i <= n; i++) dp[i] = INF;
for (i = 1; i <= n; i++) {
for (j = 0; j <= i; j++) {
dp[i] = min(dp[i], dp[i - j] + sum[j] + 2 * m);
}
}
cout << dp[n] - m << '\n';//最后一次运输不用再返回所以减去m
}
return 0;
}