题意:一个间谍要从第一个车站到第n个车站去会见另一个,在是期间有n个车站,有来回的车站,让你在时间T内时到达n,并且等车时间最短,
也就是尽量多坐车,最后输出最少等待时间。
析:这个挺复杂,首先时间是一个顺序,设d(i,j)表示时刻 i 在第 j 个车站,最少还要等待多长时间,那么边界是d(T, n) = 0。
并且有三种决策:
决策一:等着 d[i][j] = d[i + 1][j] + 1; 为什么从i + 1 过来呢? 你想一下,DP表示等待的时间,那么是不是应该倒着来呢?
决策二:有往右行驶的车 d[i][j] = min(d[i][j], d[i + t[j]][j];
决策三:有往左行驶的车 d[i][j] = min(d[i][j], d[i + t[j - 1]][j]);
代码如下:
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int INF = 0x3f3f3f3f; int main(){ int T, n, t[80], dp[205][60], m1, m2, train[255][55][2], d, k = 0; while(scanf("%d", &n) && n){ scanf("%d", &T); t[0] = 0; for(int i = 1; i < n; ++i) scanf("%d", &t[i]); scanf("%d", &m1); memset(train, false, sizeof(train)); for(int i = 0; i < m1; ++i){ scanf("%d", &d); // train[d][1][0] = true; int s = d; for(int j = 0; j < n; ++j){ s += t[j]; if(s <= T) train[s][j+1][0] = true; else break; } } scanf("%d", &m2); for(int i = 0; i < m2; ++i){ scanf("%d", &d); train[d][n][1] = true; int s = d; for(int j = n-1; j > 1; --j){ s += t[j]; if(s <= T) train[s][j][1] = true; else break; } } for(int i = 1; i < n; ++i) dp[T][i] = INF; dp[T][n] = 0; for(int i = T-1; i >= 0; --i) /// t for(int j = 1; j <= n; ++j){ /// g dp[i][j] = dp[i+1][j] + 1; if(j < n && train[i][j][0] && i + t[j] <= T) dp[i][j] = min(dp[i][j], dp[i+t[j]][j+1]); if(j > 1 && train[i][j][1] && i + t[j-1] <= T) dp[i][j] = min(dp[i][j], dp[i+t[j-1]][j-1]); } if(dp[0][1] >= INF) printf("Case Number %d: impossible\n", ++k); else printf("Case Number %d: %d\n", ++k, dp[0][1]); } return 0; }