Sicily 1264. Atomic Car Race 解题报告(动态规划)
题目传送门:1264. Atomic Car Race
思路:
如图,输入a1,a2,...an,图中共有n + 1个点,现在将这些点依次标记为0,1,2...n,现在要求找出由0到n的最短时间。
很容易发现求解这个问题的过程包含求解最优子结构的过程而且子问题是有重叠的,所以使用动态规划的方法。这里用s[n + 1][n + 1]来记录2个点之间的最短时间,任意 0 <= i <= j <= n , s[i][j]记录的是从i点到j点的最短时间,这样s[0][n]就是问题的解。
为了构建s,首先要构建一个辅助数组t[n + 1],t[k](0 <= k <= n) 表示由刚换完轮胎开始,连续不换胎行驶k公里的路程需要的时间。由于t[k]可以利用t[k - 1]的值和题目给出公式算出,所以构建t数组需要时间O(n).
下面用自底向上的方法构建s。要计算s[i][j],假设在i,j之间的某点k进行换胎可得最优解,有s[i][j] = s[i][k] + s[k][j] + b.为了找出k点可以遍历一次i到j之间的所有点都计算一次即可。当然s[i][j]也可能等于t[a[j] - a[i]](不用换胎的情况)。有了递推公式,现在要验证在计算s[i][j]时所有有关的子问题都已经算出。假设i到j的长度为l,由于k在i,j之间,显然i到k的长度和k到j的长度都小于l,这样只要随l由小到大的构建s即可。
注意最后输出要用fixed保持足够精度,一开始没有使用结果WA.
代码:
1 #include<iostream>
2 using namespace std;
3
4 int main(){
5 int n;
6 while(cin >> n && n != 0){
7 int a[n + 1];
8 a[0] = 0;
9 for(int i = 1;i <= n;i++)
10 cin >> a[i];
11 int r;
12 double b,v,e,f;
13 cin >> b >> r >> v >> e >> f;
14 double t[a[n] + 1]; //t[k] is the total time the car moves k kilometers without changing tires.
15 t[0] = 0;
16 for(int i = 1;i <= a[n];i++){
17 if(i - 1 < r)
18 t[i] = t[i - 1] + 1 / (v - f * (r - (i - 1)));
19 else
20 t[i] = t[i - 1] + 1 / (v - e * ((i - 1) - r));
21 }
22 double s[n + 1][n + 1]; //s[i][j] is the shortest time move from point ai to aj.
23 //calculate s in button-up method.
24 for(int i = 0;i < n + 1;i++)
25 s[i][i] = 0;
26 for(int l = 1;l <= n;l++){//length from 1 to n.
27 for(int i = 0;i <= n - l;i++){
28 int j = i + l;
29 double min = t[a[j] - a[i]];
30 for(int k = i + 1;k < j;k++){
31 if(b + s[i][k] + s[k][j] < min){
32 min = b + s[i][k] + s[k][j];
33 }
34 }
35 s[i][j] = min;
36 }
37 }
38 cout << fixed << s[0][n] << endl;
39 }
40 return 0;
4