过桥
过桥
Time Limit : 3000/1000ms (Java/Other) Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 2 Accepted Submission(s) : 2
Font: Times New Roman | Verdana | Georgia
Font Size: ← →
Problem Description
GDOI工作组遇到了一个运输货物的问题,现在有N辆车要顺序通过一个单项的小桥,由于小巧太窄了,不能有两辆车并排通过,所以在桥上不能超车,另外,由于小桥建造的时间已经很久,所以只能承受有限的重量,记为Max(吨),即任意时刻在桥上行驶的车辆的总重量不能超过Max(吨)。所以,车辆在过桥的时候必须要有管理员控制,将这N辆车按初始的顺序分组,每次让一个组过桥,并且只有一个组中所有的车辆全部过桥以后才让下一组车辆上桥,现在,每辆沉的重量和最大的速度是已知的,而每组车的过桥时间有该组中速度最慢的那辆车决定。
现在请你编一个程序,将这N辆车分组,使得全部车辆通过小桥的时间最短。
现在请你编一个程序,将这N辆车分组,使得全部车辆通过小桥的时间最短。
Input
第1行有3个数,分别为Max(吨),Len(桥的长度,单位:Km)。N(3个数之间用一个或多个空格分开。)接下来有N行。每行两个数,第i行当两个数分别表示第i辆车的重量(吨)和最大速度(Km/h).
注意:所有的输入都为整数,并且任何一辆车的重量都不会超过Max。
注意:所有的输入都为整数,并且任何一辆车的重量都不会超过Max。
Output
只有一行,输出全部车辆通过小桥的最短时间(minute),精确到小数点后一位。
Sample Input
100 5 10 40 25 50 20 50 20 70 10 12 50 9 70 49 30 38 25 27 50 19 70
Sample Output
75.0
解释:
题目首先说明这n辆车的顺序是不可以被改变的,能被改变的是,n辆车的不同分组。从而得到最短的时间。这是一个动态规划题目。当第1...k辆车以最小的时间通过时,k+1...n 也可以是最小时间通过。m..n辆车可以由两组车队来一次通过,其中[m, k]是最优的,[k+1, n]也是最优的。那么[m, n]也是最优的。
我看了别人的博客才知道状态转移方程,其实对于动态规划题,我认识状态的描述是比较重要的,知道了状态的含义就可以去思考状态转移方程,从而得到解,但是要怎么去想这个状态含义。我经常想不到。可能是做题少了吧。
对于这个题目,使用两个状态,第一个 t[i][j]表示,[i,j] 区间内,车辆通过所需要的最大时间。第二个f[i]表示,当第 i 辆车通过时所要的最小时间。那么结果就是f[n]。
对于第一个t, 那么t[i][i] 就是第 i 辆车自己单个通过的时间,t[i][j] = max(t[j][j], t[i][j-1]). t[j][j]是自己的当前时间,t[i][j-1]就是表示和[i, j-1]区间的车队一起通过。
if (pre[i] - pre[j-1] <= 最大承重量) f[i] = min(f[i], f[j-1] + t[j][i]) .其中 pre[i] 是表示前缀和。第 i 辆车通过时所要的最小时间是,当前车辆和 前 第 j 辆车一起走,是pre[j-1]而不是pre[j] 的原因是,per表示前缀和,第 i 辆车和 第 j 辆车一起走时,如果是pre[j] 那么就没有考虑第 j 辆车的重量了。f[j-1] + t[j][i] 表示也是一样的道理,如果是 f[j] 的话,将会重复计算 第 j 辆车的时间。
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 const int N = 1010; 6 7 unsigned long long int pre_sum[N], v, m, len; 8 9 double t[N][N]; 10 double f[N]; 11 12 int main() { 13 int n; 14 while (cin >> m >> len >> n) { 15 pre_sum[0] = 0; 16 for (int i = 1; i <= n; i++) { 17 cin >> pre_sum[i] >> v; 18 pre_sum[i] += pre_sum[i-1]; 19 t[i][i] = double(double(len) / double(v)); 20 } 21 22 for (int i = 1; i < n; i++) { 23 for(int j = i + 1; j <= n; j++) { 24 t[i][j] = max(t[j][j], t[i][j-1]); 25 } 26 } 27 f[1] = t[1][1]; 28 29 for (int i = 2; i <= n; i++) { 30 f[i] = 1e9; 31 for (int j = i; j >= 1; j--) { 32 if (pre_sum[i] - pre_sum[j-1] > m) break; 33 f[i] = min(f[i], f[j-1] + t[j][i]); 34 } 35 } 36 printf("%.1lf\n", f[n]*60.00); 37 } 38 return 0; 39 }