简介:
有n个车站,有M1辆火车向右开,M2辆火车向左开,
你可以在车站上自由换车,T时刻要在n号火车站,问最短的等待时间
分析:
时间是单向流逝的,这就是一个天然的 “序”
影响到当前决策的只有时间和所处的车站,那我们就把这两个条件加到状态转移中去
设f[i][j]表示时刻i,在车站j的最短等待时间
每个状态都有3个决策:
- 等待一分钟
- 如果有向右开的火车,跳上车
- 如果有向左开的火车,跳上车
为了快速判断是否有车可坐,我们预处理一个train数组:
train[t][i][1]表示时刻t,在车站i有没有向右开的车
train[t][i][0]表示时刻t,在车站i有没有向左开的车
边界情况:f[0][1]=0
tip
注意如果时间太靠后(超过T),我们就不用往train数组里记录了(防止RE)
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int INF=0x33333333;
int n,T;
int m1,m2;
int a[55];
int train[205][55][2];
int f[205][55]; //时刻i在车站j
int get(int t,int i,int opt)
{
if (opt==1) return a[i];
else return a[i-1];
}
void doit()
{
int i,j;
memset(f,0x33,sizeof(f));
f[0][1]=0;
for (i=0;i<=T;i++)
for (j=1;j<=n;j++)
{
f[i+1][j]=min(f[i+1][j],f[i][j]+1);
if (j<n&&train[i][j][1])
{
int r=get(i,j,1);
f[i+r][j+1]=min(f[i+r][j+1],f[i][j]);
}
if (j>1&&train[i][j][0])
{
int r=get(i,j,0);
f[i+r][j-1]=min(f[i+r][j-1],f[i][j]);
}
}
}
int main()
{
int cnt=0;
while (scanf("%d",&n)!=EOF&&n)
{
memset(train,0,sizeof(train));
scanf("%d",&T);
for (int i=1;i<n;i++) scanf("%d",&a[i]);
scanf("%d",&m1);
for (int i=1;i<=m1;i++)
{
int x;
scanf("%d",&x);
if (x>T) continue;
train[x][1][1]=1; //train[t][i][0/1]时刻t车站i有没有车
for (int j=1;j<n;j++)
{
x+=a[j];
if (x>T) break;
train[x][j+1][1]=1;
}
}
scanf("%d",&m2);
for (int i=1;i<=m2;i++)
{
int x;
scanf("%d",&x);
if (x>T) continue;
train[x][n][0]=1;
for (int j=n-1;j>=1;j--)
{
x+=a[j];
if (x>T) break;
train[x][j][0]=1;
}
}
doit();
printf("Case Number %d: ",++cnt);
if (f[T][n]==INF) printf("impossible\n");
else printf("%d\n",f[T][n]);
}
return 0;
}