题面: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 << " "; } printf("Case Number %d: ",ca++); if(dp[0][1]>=INF) printf("impossible "); else printf("%d ",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 << " "; } printf("Case Number %d: ",ca++); if(dp[T][N]>=INF) printf("impossible "); else printf("%d ",dp[T][N]); } return 0; }