有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;
}