- 题目描述:
-
在某条线路上有N个火车站,有三种距离的路程,L1,L2,L3,对应的价格为C1,C2,C3.其对应关系如下:距离s 票价0<S<=L1 C1L1<S<=L2 C2L2<S<=L3 C3输入保证0<L1<L2<L3<10^9,0<C1<C2<C3<10^9。每两个站之间的距离不超过L3。当乘客要移动的两个站的距离大于L3的时候,可以选择从中间一个站下车,然后买票再上车,所以乘客整个过程中至少会买两张票。现在给你一个 L1,L2,L3,C1,C2,C3。然后是A B的值,其分别为乘客旅程的起始站和终点站。然后输入N,N为该线路上的总的火车站数目,然后输入N-1个整数,分别代表从该线路上的第一个站,到第2个站,第3个站,……,第N个站的距离。根据输入,输出乘客从A到B站的最小花费。
- 输入:
-
以如下格式输入数据:L1 L2 L3 C1 C2 C3A BNa[2]a[3]……a[N]
- 输出:
-
可能有多组测试数据,对于每一组数据,根据输入,输出乘客从A到B站的最小花费。
- 样例输入:
-
1 2 3 1 2 3 1 2 2 2
- 样例输出:
-
2
这道题真是一个惨痛的回忆。
开始的思路是普通的动态规划思路,即经典的分割问题,最后通过的代码如下1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <string> 5 #define MAX 300 6 #define inf 10000000009 7 8 long long minCost[MAX][MAX]; 9 long long dis[MAX][MAX]; 10 long long dis0[MAX]; 11 12 int main(int argc, char const *argv[]) 13 { 14 long long L1, L2, L3, C1, C2, C3; 15 //freopen("input.txt","r",stdin); 16 while(scanf("%lld %lld %lld %lld %lld %lld",&L1, &L2, &L3, &C1, &C2, &C3) != EOF) 17 { 18 int A, B; 19 int N; 20 scanf("%d %d",&A,&B); 21 scanf("%d",&N); 22 dis0[1] = 0; 23 for(int i = 2; i <= N; i++) { 24 scanf("%lld",&dis0[i]); 25 } 26 for(int l = 1; l <= N - 1; l++) { 27 //length from 1 to N - 1 28 for(int i = 1; i <= N - l; i++) { 29 //start from i to N - l 30 int j = i + l; 31 //end is i + l 32 dis[i][j] = dis0[j] - dis0[i]; 33 if(dis[i][j] <= L1) { 34 minCost[i][j] = C1; 35 } 36 else if(dis[i][j] <= L2) { 37 minCost[i][j] = C2; 38 } 39 else if(dis[i][j] <= L3) { 40 minCost[i][j] = C3; 41 } 42 else { 43 minCost[i][j] = inf; 44 } 45 46 for(int k = i + 1; k <= j-1; k++) { 47 long long int q = minCost[i][k] + minCost[k][j]; 48 if(q < minCost[i][j]) { 49 minCost[i][j] = q; 50 } 51 } 52 } 53 } 54 if(A < B) { 55 printf("%lld ",minCost[A][B]); 56 } 57 else if(A > B){ 58 printf("%lld ",minCost[B][A]); 59 } 60 else { 61 printf("%d ",0); 62 } 63 64 } 65 return 0; 66 }
但代码一开始提交了n次都没有通过,经过很长时间的排查,终于发现了原因。一开始我设的inf是
1000000009,WA改成了
10000000009后就AC了。
之后我发现没必要去算出每两个点之间的最小花费,只需要计算出从A到B之间的最小花费即可,dis数组也不需要
代码如下:
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <string> 5 #define MAX 300 6 #define inf 10000000009 7 8 long long minCost[MAX][MAX]; 9 long long dis0[MAX]; 10 11 int main(int argc, char const *argv[]) 12 { 13 long long L1, L2, L3, C1, C2, C3; 14 //freopen("input.txt","r",stdin); 15 while(scanf("%lld %lld %lld %lld %lld %lld",&L1, &L2, &L3, &C1, &C2, &C3) != EOF) 16 { 17 int A, B; 18 int N; 19 scanf("%d %d",&A,&B); 20 scanf("%d",&N); 21 22 for(int i = 2; i <= N; i++) { 23 scanf("%lld",&dis0[i]); 24 } 25 if(A > B) { 26 int temp = A; 27 A = B; 28 B = temp; 29 } 30 long long n = B - A; 31 dis0[1] = 0; 32 minCost[A][A] = 0; 33 for(int l = 1; l <= n; l++) { 34 //length from 1 to N - 1 35 for(int i = A; i <= A + n - l; i++) { 36 //start from i to N - l 37 int j = i + l; 38 //end is i + l 39 long long temp = dis0[j] - dis0[i]; 40 if(temp <= L1) { 41 minCost[i][j] = C1; 42 } 43 else if(temp <= L2) { 44 minCost[i][j] = C2; 45 } 46 else if(temp <= L3) { 47 minCost[i][j] = C3; 48 } 49 else { 50 minCost[i][j] = inf; 51 } 52 53 for(int k = i + 1; k <= j-1; k++) { 54 long long int q = minCost[i][k] + minCost[k][j]; 55 if(q < minCost[i][j]) { 56 minCost[i][j] = q; 57 } 58 } 59 } 60 } 61 printf("%lld ",minCost[A][B]); 62 63 } 64 return 0; 65 }
但是我们研究一下会发现,如果两地的距离小于L3,则它们之间的最小花费必然在C1,C2,C3之间,所以若将minCost改为一维数组,将i作为中间点,j作为终点,当i到j的距离小于L3时,minCost[j] = min (minCost[j], minCost[i] + Ci); 所以遍历i时,选取与其距离小于L3的j,即可。代码如下:
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <string> 5 #define MAX 150 6 #define inf 10000000009 7 8 long long minCost[MAX]; 9 long long dis0[MAX]; 10 11 int main(int argc, char const *argv[]) 12 { 13 long long L1, L2, L3, C1, C2, C3; 14 //freopen("input.txt","r",stdin); 15 while(scanf("%lld %lld %lld %lld %lld %lld",&L1, &L2, &L3, &C1, &C2, &C3) != EOF) 16 { 17 int A, B; 18 int N; 19 20 scanf("%d %d",&A,&B); 21 scanf("%d",&N); 22 dis0[1] = 0; 23 for(int i = 2; i <= N; i++) { 24 scanf("%lld",&dis0[i]); 25 minCost[i] = inf; 26 } 27 if(A > B) { 28 int temp = A; 29 A = B; 30 B = temp; 31 } 32 minCost[A] = 0; 33 for(int i = A; i < B; i++) { 34 for(int j = i + 1; j <= B; j++) { 35 long long int temp; 36 if(dis0[j] - dis0[i] <= L1) { 37 temp = C1; 38 } 39 else if(dis0[j] - dis0[i] <= L2) { 40 temp = C2; 41 } 42 else if(dis0[j] - dis0[i] <= L3) { 43 temp = C3; 44 } 45 else { 46 break; 47 } 48 long long q = minCost[i] + temp; 49 if(minCost[j] > q) { 50 minCost[j] = q; 51 } 52 } 53 } 54 printf("%lld ",minCost[B]); 55 } 56 return 0; 57 }
因为两个站的最大距离不超过L3,所以从A站到j站,中间必然会经过距离j站距离小于L3的某站,故minCost[j]在遍历时中间的分割点必然在这些站之间,所以可以这样化简