有N个地铁站,每个地铁站之间的行驶是双向的,并且需要的时间也是固定的,然后又m1列火车在不同的时段从左侧发出,有m2列火车在不同的时段从右侧发出, 现在问你经过T时间后,到达站点n过程中一共在站台等待的时间的最小值是多少。
预处理出在第 i 时间 j 站台经过经过多少时间到达 j+1 和 j-1 的 l 和 r 数组,刷表法,开始进行状态转移,dp[i][j]表示在第i时间第j站台的最小值,那么先把他们全都赋为INF,dp[0][1]即开始位置是0,设这个时间这个站台刚好有向右的地铁耗时为t, 那么 dp[i+t][j+1] = min(dp[i+t][j+1], dp[i][j]) (i+t <= T && j+1 <= N) ,往左同理,别忘了还有不坐地铁的情况,如果当前的状态可以到达,就dp[i+1][j] = min(dp[i+1][j], dp[i][j])。
最后判断dp[T][N]是否是INF就行,如果是的话就说明无法转移到这个状态,输出impossible,否则输出dp[T][N]。
动态规划题目的写法多的不得了,不是看了别人的题解就一定要怎么怎么写,比如这题还可以从n站台往1站台转移。重要的是思路,也就是状态转移。
判断是否是合法转移的时候一定要多想想,小心数组越界!
#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
int N, T, t[210], l[210][60], r[210][60], dp[210][60];
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.precision(10);
cout << fixed;
#ifdef LOCAL_DEFINE
freopen("input.txt", "r", stdin);
#endif
int kase = 1;
while (cin >> N) {
if (!N) break;
cin >> T;
for (int i = 1; i <= N-1; ++i) cin >> t[i];
int m, x;
memset(l, 0, sizeof(l));
memset(r, 0, sizeof(r));
cin >> m;
for (int i = 0; i < m; ++i) {
cin >> x;
int idx = 1, now = x;
while (idx < N && now <= T) {
r[now][idx] = t[idx];
now += t[idx];
++idx;
}
}
cin >> m;
for (int i = 0; i < m; ++i) {
cin >> x;
int idx = N, now = x;
while (idx > 1 && now <= T) {
l[now][idx] = t[idx-1];
now += t[idx-1];
--idx;
}
}
memset(dp, 0x3f, sizeof(dp));
dp[0][1] = 0;
for (int i = 0; i < T; ++i) {
for (int j = 1; j <= N; ++j) {
if (dp[i][j] != INF) dp[i+1][j] = min(dp[i+1][j], dp[i][j] + 1);
int temp = r[i][j];
if (j < N && temp && i + temp <= T) dp[i+temp][j+1] = min(dp[i+temp][j+1], dp[i][j]);
temp = l[i][j];
if (j > 1 && temp && i + temp <= T) dp[i+temp][j-1] = min(dp[i+temp][j-1], dp[i][j]);
}
}
cout << "Case Number "<< kase++ << ": ";
if (dp[T][N] == INF) cout << "impossible" << '\n';
else cout << dp[T][N] << '\n';
}
#ifdef LOCAL_DEFINE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}