题目链接:http://fastvj.rainng.com/contest/306591#problem/A
题目大意:
某城市的地铁是线性的,有n(2≤n≤50)个车站,从左到右编号为1~n。有M1辆列车从 第1站开始往右开,还有M2辆列车从第n站开始往左开。在时刻0,Mario从第1站出发,目的 是在时刻T(0≤T≤200)会见车站n的一个间谍。在车站等车时容易被抓,所以她决定尽量躲 在开动的火车上,让在车站等待的总时间尽量短。列车靠站停车时间忽略不计,且Mario身 手敏捷,即使两辆方向不同的列车在同一时间靠站,Mario也能完成换乘。
输入第1行为n,第2行为T,第3行有n-1个整数t1, t2,…, tn-1(1≤ti≤70),其中ti表示地 铁从车站i到i+1的行驶时间(两个方向一样)。第4行为M1(1≤M1≤50),即从第1站出发 向右开的列车数目。第5行包含M1个整数d1, d2,…, dM1(0≤di≤250,di<di+1),即各列车的 出发时间。第6、7行描述从第n站出发向左开的列车,格式同第4、5行。输出仅包含一行, 即最少等待时间。无解输出impossible。
思路:
题解:时间是单向流逝的,是一个天然的“序”。影响到决策的只有当前时间和所处的车站,
所以可以用d(i,j)表示时刻i,你在车站j(编号为1~n),最少还需要等待多长时间。
边界条件 是d(T,n)=0,其他d(T,i)(i不等于n)为正无穷。有如下3种决策。
决策1:等1分钟。
决策2:搭乘往右开的车(如果有)。
决策3:搭乘往左开的车(如果有)。
我的思路:
题解是从时间T推到1.相对难理解。所以我从1推到T。
边界条件 是d(0,1)=0,其他d(T,i)(i不等于n)为正无穷。有如下3种决策。
决策1:等1分钟。
决策2:搭乘往右开的车(如果有)。
决策3:搭乘往左开的车(如果有)。
上面的代码中有一个vis数组,其中vis[t][i][0]表示时刻t,在车站i是否有往右开的火车,
vis[t][i][1]类似,不过记录的是往左开的火车。输入预处理一下。
代码:
#include<bits/stdc++.h>
#define LL long long
using namespace std;
int t[1000];
int c[1000];
int d[1000];
int vis[2005][55][2];
int dp[2005][55];
int main()
{
int n, T, m1, m2, CUT=1;
while(scanf("%d",&n),n)
{
memset(vis, 0, sizeof(vis));
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",&c[i]);
int g=c[i];
for(int j=1;j<=n;j++)
{
vis[g][j][0]=1;
g+=t[j];
}
}
scanf("%d",&m2);
for(int i=1;i<=m2;i++)
{
scanf("%d",&d[i]);
int g=d[i];
for(int j=n;j>=1;j--)
{
vis[g][j][1]=1;
g+=t[j-1];
}
}
for(int p=0;p<=T;p++)
{
for(int i=1;i<=n;i++)
{
dp[p][i]=(1<<31)-1;
}
}
dp[0][1]=0;
for(int i=0;i<T;i++)
{
for(int j=1;j<=n;j++)
{
if(dp[i][j]!=(1<<31)-1)
{
dp[i+1][j]=min(dp[i][j]+1, dp[i+1][j]);//等待
if(j<n&&i+t[j+1]<=T&&vis[i][j][0])//往右开
{
dp[i+t[j]][j+1]=min(dp[i][j], dp[i+t[j]][j+1]);
}
if(j>1&&i+t[j-1]<=T&&vis[i][j][1])//往左开
{
dp[i+t[j-1]][j-1]=min(dp[i][j], dp[i+t[j-1]][j-1]);
}
}
}
}
if(dp[T][n]==(1<<31)-1)
{
printf("Case Number %d: impossible\n",CUT++);
}
else
{
printf("Case Number %d: %d\n",CUT++,dp[T][n]);
}
}
return 0;
}