題面:https://vjudge.net/problem/UVA-1025
思路:
紫書上的dp入門題,蒟蒻看了好久才看明白,下面就是思路。
首先要用一個三維數組has_train[i][j][k]表示在i時刻第j個站台是否有從左到右或從右到左的車(k = 0為從左到右,k = 1為從右到左)。
決策一共有3種
決策1:在站台等一分鍾。
決策2:搭乘向右開的車(如果有)
決策3:搭乘向左開的車(如果有)
建立dp數組dp[i][j]
首先是逆向遞推,這也是lrj的思路。
此時dp[i][j]的定義是在i時刻,從j站台到n站台的最小停留時間。
從上面的三個決策,我們就可以得到遞推式
dp[i][j] = min(dp[i+1][j],dp[i+t[j]][j+1],dp[i+t[j-1]][j-1])
因為決策2,3都是需要條件轉移的,所以在轉移時要加入判斷條件,詳細細節可以看下面代碼。
初始化dp[T][n] = 0,最后答案是dp[0][1]。
然后這道題還可以正向推
這個時候dp[i][j]的含義就是i時刻從1站台到j站台的最小停留時間
轉移方程也對應發生了變化
dp[i][j] = min(dp[i-1][j],dp[i-t[j-1]][j-1],dp[i-t[j]][j+1])
要注意我們轉移的方向變了所以判斷決策2,3的條件也就變了。
初始化為dp[0][1] = 0,答案是dp[T][N]。
代碼1:
#include <bits/stdc++.h> using namespace std; int dp[300][100];//時間為i時在j站台到n站台所花費的時間。 const int INF = 0x3f3f3f3f; bool has_train[300][100][2];//dp[i][j][0],mean there is a train which from left to right in j in i time //dp[i][j][1],mean there is a train which from right to left in j in i time int t[100]; int d1[100],d2[100]; int main() { int N,T,M1,M2; int ca =1; while(scanf("%d",&N)&&N) { scanf("%d",&T); for(int i = 1;i<N;++i) scanf("%d",&t[i]); scanf("%d",&M1); for(int i = 1;i<=M1;++i) scanf("%d",&d1[i]); scanf("%d",&M2); for(int i =1;i<=M2;++i) scanf("%d",&d2[i]); memset(has_train,false,sizeof(has_train)); for(int i = 1;i<=N;++i) dp[T][i] =INF; dp[T][N] = 0; for(int i =1;i<=M1;++i) { int x = d1[i]; for(int j = 1;j<=N;++j) { if(x>T) break; has_train[x][j][0] = true; x+=t[j]; } } for(int i =1;i<=M2;++i) { int x = d2[i]; for(int j =N;j>=1;--j) { if(x>T) break; has_train[x][j][1] = true; x+=t[j-1]; } } for(int i = T-1;i>=0;--i) { for(int j = 1;j<=N;++j) { dp[i][j] = dp[i+1][j]+1;//決策1 if(j>1&&has_train[i][j][1]&&i+t[j-1]<=T)//決策3 { dp[i][j] = min(dp[i][j],dp[i+t[j-1]][j-1]); } if(j<N&&has_train[i][j][0]&&i+t[j]<=T)//決策2 dp[i][j] = min(dp[i][j],dp[i+t[j]][j+1]); } // cout << i << ": "; // for(int j =1 ;j<=N;++j) // cout << dp[i][j] << " "; // cout << "\n"; } printf("Case Number %d: ",ca++); if(dp[0][1]>=INF) printf("impossible\n"); else printf("%d\n",dp[0][1]); } return 0; }
代碼2:
#include <bits/stdc++.h> using namespace std; int dp[300][100];//時間為i時在1站台到j站台所花費的時間。 const int INF = 0x3f3f3f3f; bool has_train[300][100][2]; int t[100]; int d1[100],d2[100]; int main() { int N,T,M1,M2; int ca =1; while(scanf("%d",&N)&&N) { scanf("%d",&T); for(int i = 1;i<N;++i) scanf("%d",&t[i]); scanf("%d",&M1); for(int i = 1;i<=M1;++i) scanf("%d",&d1[i]); scanf("%d",&M2); for(int i =1;i<=M2;++i) scanf("%d",&d2[i]); memset(has_train,false,sizeof(has_train)); for(int i = 1;i<=N;++i) dp[0][i] =INF; dp[0][1] = 0; for(int i =1;i<=M1;++i) { int x = d1[i]; for(int j = 1;j<=N;++j) { if(x>T) break; has_train[x][j][0] = true; x+=t[j]; } } for(int i =1;i<=M2;++i) { int x = d2[i]; for(int j =N;j>=1;--j) { if(x>T) break; has_train[x][j][1] = true; x+=t[j-1]; } } for(int i = 1;i<=T;++i) { for(int j = 1;j<=N;++j) { dp[i][j] = dp[i-1][j]+1;//決策1 if(j<N&&has_train[i][j][1]&&i-t[j]>=0)//決策3 { dp[i][j] = min(dp[i][j],dp[i-t[j]][j+1]); } if(j>1&&has_train[i][j][0]&&i-t[j-1]>=0)//決策2 dp[i][j] = min(dp[i][j],dp[i-t[j-1]][j-1]); } // cout << i << ": "; // for(int j =1 ;j<=N;++j) // cout << dp[i][j] << " "; // cout << "\n"; } printf("Case Number %d: ",ca++); if(dp[T][N]>=INF) printf("impossible\n"); else printf("%d\n",dp[T][N]); } return 0; }