题意:有n(2<=n<=50)个车站,从左到右编号为1~n。有M1辆列车从第一站开始往右开,还有M2辆列车从第n站开始往左开。在时刻0某人从第一站出发,目的是在时刻T(0<=T<=200)会见车站n的一个间谍。在车站等车时容易被抓,所以这个人应尽量躲在开动的火车上,让在车站等待的时间应该尽量短。列车靠站停车时间忽略不计,并且这个人身手敏捷,即使两辆不同方向的列车在同一时间靠站,也能完成换乘。
输入第一行为n,第2行为T,第3行有n-1个整数ti(ti<=70),其中ti表示地铁从车站i到i+1的行驶时间(两个方向一样)。第4行为M1,(1<=M1<=50),即从第一站出发向右开的列车数目。第五行包含M1个整数dm(0<=dm<=250,di<d(i+1)),即各列车的出发时间。第6,7行描述从第n站出发向左开的列车,格式同第4,5行,输出仅包含一行,即最少等待时间。无解输出impossible。
思路:时间是单向流逝的,是一个天然的“序”。影响到决策的只有当前时间和所处的车站。所以可用d[i][j]表示时刻i,在车站j(序号为1~n)还需要等待多长时间,边界条件是d[T][n] = 0,其他d[T][i] = INF,有三种决策
1.等1分钟
2.搭乘向右开的车(如果有)
3.搭乘向左开的车(如果有);
has_train[i][j][0]表示时刻i在车站j是否有向右开的火车,has_train[i][j][1]表示时刻i在车站j是否有向左开的火车
#include <bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define INF 0x3f3f3f3f
#define mod 1000000007;
using namespace std;
const int maxn = 52;
const int maxt = 202;
int n,T,l,r,x;
int t[maxn],dp[maxt][maxn];
int has_train[maxt][maxn][3];
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
int main()
{
int kase = 1;
while(scanf("%d",&n) && n)
{
scanf("%d",&T);
memset(has_train,0,sizeof(has_train));
for(int i = 1;i < n;i++) scanf("%d",&t[i]);
scanf("%d",&l);
for(int i = 1;i <= l;i++)
{
scanf("%d",&x);
for(int j = 1;j < n;j++)
{
has_train[x][j][0] = 1;
x += t[j];
}
}
scanf("%d",&r);
for(int i = 1;i <= r;i++)
{
scanf("%d",&x);
for(int j = n;j > 1;j--)
{
has_train[x][j][1] = 1;
x += t[j - 1];
}
}
dp[T][n] = 0;
for(int i = 1;i < n;i++) dp[T][i] = INF;
for(int i = T - 1;i >= 0;i--)
{
for(int j = 1;j <= n;j++)
{
dp[i][j] = dp[i + 1][j] + 1;
if(j < n && has_train[i][j][0] && i + t[j] <= T) dp[i][j] = min(dp[i][j],dp[i + t[j]][j + 1]);
if(j > 1 && has_train[i][j][1] && i + t[j - 1] <= T) dp[i][j] = min(dp[i][j],dp[i + t[j - 1]][j - 1]);
}
}
if(dp[0][1] >= INF) printf("Case Number %d: impossible\n",kase++);
else printf("Case Number %d: %d\n",kase++,dp[0][1]);
}
return 0;
}