过桥

过桥

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辆车分组,使得全部车辆通过小桥的时间最短。

Input

第1行有3个数,分别为Max(吨),Len(桥的长度,单位:Km)。N(3个数之间用一个或多个空格分开。)接下来有N行。每行两个数,第i行当两个数分别表示第i辆车的重量(吨)和最大速度(Km/h).
注意:所有的输入都为整数,并且任何一辆车的重量都不会超过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 }
View Code

 

posted @ 2019-07-19 08:25  龚政  阅读(337)  评论(0编辑  收藏  举报