刷表法,也就是对于每个状态i,更新f(i)所影响到的状态,书上是逆推,我用的是正推,道理都是一样的,对于向左的列车,用到的是第j+1个车站的状态,但一开始,人只在第1个车站,所以把其他所有个车站的状态设为无穷,所以只有在j+1已被算过的情况下,j+1前面的车站乘坐向左的列车才有意义。
#include<bits/stdc++.h>
#include<cmath>
#define inf 0x3f3f3f3f
using namespace std;
int t[75];
int dp[1005][55]; //时刻,车站
int has_train[1005][55][2]; //时刻,车站,0表示向右的列车,1表示向左的列车
void dp1(int n,int T){
for(int i=1;i<=T;i++)
for(int j=1;j<=n;j++)
{
dp[i][j]=dp[i-1][j]+1; //等待一个单位
if(j>1 && has_train[i][j][0] && i+t[j]<=T) //坐向右的列车
dp[i][j]=min(dp[i][j],dp[i-t[j-1]][j-1]);
if(j<n && has_train[i][j][1] && i+t[j-1]<=T) //坐向左的列车
dp[i][j]=min(dp[i][j],dp[i-t[j]][j+1]);
}
}
int main()
{
int n,T,m,flag;
int kase=1;
while(scanf("%d",&n) && n ){
memset(has_train,0,sizeof(has_train));
memset(dp,0,sizeof(dp));
memset(t,0,sizeof(t));
for(int i=1;i<=n;i++) dp[0][i]=inf;
dp[0][1]=0;
scanf("%d",&T); //时间
for(int i=1;i<n;i++)
scanf("%d",&t[i]); //ti到ti+1车站需要的时间。
scanf("%d",&m); //有几列
for(int i=1; i<=m; i++)
{
scanf("%d",&flag);
for(int j=1;j<=n;j++)
{
flag+=t[j-1];
has_train[flag][j][0]=1;
}
}
scanf("%d",&m);
for(int i=1; i<=m; i++)
{
scanf("%d",&flag);
for(int j=n;j>=1;j--)
{
flag+=t[j];
has_train[flag][j][1]=1;
}
}
dp1(n,T);
if(dp[T][n]>=inf)
printf("Case Number %d: impossible\n",kase++);
else
printf("Case Number %d: %d\n",kase++,dp[T][n]);
}
}