算法竞赛入门经典 第二版 的第一个动规例题。 在思考了好久之后 终于写完 还是按照书中代码写的。
现在脑子里还想不出完整的模型,
对这个题的理解, 就是在某一个状态下, 都有好几个状态可以让自己选择去走, 然后每一个都去试试, 最终维护最小值
这个题是有 n个车站,从左边都有每隔一段时间 会有一次发车, 右边也是, 这个人必须在指定的时间 指定的地点 到达某处,
所以会有了 下车 , 左走 等待 右走的情况。
用 have_train【a】【b】【c】 三维来描述某一个站点 某一时刻 是否有车 有的话 是向哪走,
因为终点的状态很确定 必然是 dp【time】【n】 即 在 time 时间的时候正好达到n站点
我们可以 从 终点的状态 往起始的状态转化, 一步步走就可以了。
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <string>
#include <map>
#include <vector>
#include <set>
#include <cmath>
#include <stack>
#include <queue>
#include <cstring>
#define ll long long;
#define maxn 300 + 10
#define INF 10000000
using namespace std;
int main(){
int n,counts = 0;
while(scanf("%d",&n) && n){
int ti;
int go[maxn];
int have_train[maxn][maxn][2];
memset(have_train,0,sizeof(have_train));
scanf("%d",&ti);
for(int i = 1 ; i < n ; i ++)
scanf("%d",&go[i]);
int num1;
scanf("%d",&num1);
for(int i = 0 ; i < num1 ; i++){
int start ;
scanf("%d",&start);
have_train[start][1][0] = 1;
for(int j = 1 ; j < n; j ++){
if(go[j] + start <= ti)
have_train[go[j] + start][j + 1][0] = 1;
start += go[j];
}
}
int num2;
scanf("%d",&num2);
for(int i = 0 ; i < num2 ; i++){
int start ;
scanf("%d",&start);
have_train[start][n][1] = 1;
for(int j = n; j > 1 ; j --)
if(go[j - 1] + start <= ti){
have_train[go[j - 1] + start][j - 1][1] = 1;
start += go[j - 1];
}
}
int dp[maxn][maxn];
for(int i = 1 ; i < n ; i++) dp[ti][i] = INF;
dp[ti][n] = 0;
for(int i = ti - 1; i >= 0 ; i --){
for(int j = 1 ; j <= n ; j++){
dp[i][j] = dp[i + 1][j] + 1;
if(j < n && i + go[j] <= ti && have_train[i][j][0]){
dp[i][j] = min(dp[i][j],dp[i + go[j]][j + 1]);
}
if(j > 1 && i + go[j - 1] <= ti && have_train[i][j][1]){
dp[i][j] = min(dp[i][j],dp[i + go[j - 1]][j - 1]);
}
}
}
if(dp[0][1] >= INF)
printf("Case Number %d: impossible\n",++counts);
else
printf("Case Number %d: %d\n",++counts,dp[0][1]);
}
return 0;
}