紫书这本丧心病狂经典入门的书,居然可以把Final的题目作为例题的第1题!
大概说下题意吧:
一共有n站车站(1~n),间谍从1站出发。
需要在时间t时到达n站
给出每一站到下一站的花费时间
从1站、n站发车的车数以及车次
其中换乘不需要时间
每次间谍可以等待一个时间
或者坐车到前一站或者后一站(如果有车)
求最小需要等待的时间
/*
Name:例题9-1 A spy in the Metro(UVa 1025 Final2003)
Author:wyz
Date:2019/4/23 17:43:18
Note:
*/
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;
typedef long long ll;
const int M1=55,M2=205,INF=1e6;
int times[M1],to[M1],back[M1];
//在时刻i,j车站,是否有开往左右的车
int has_train[M2][M1][2];
/*
n:车站的个数
t:约定时间
m1:从1站发车(向右开)的数量
m2:从n站发车(向左开)的数量
times:每个站到之后一个站的时间
to[]:从1站发展的时刻表
back[]:从n站发车的时刻表
M1:发车数的最大值
M2:约定时间的最大值
时间是单项流逝的,是一个天然的"序"
*/
int dp[M2][M1];
int main()
{
int n,t,m1,m2,temp,kase=0;
while(scanf("%d",&n) && n)
{
//初始化has_train表,任何时候都没有车
memset(has_train,0,sizeof(has_train));
scanf("%d",&t);//读入约定时间
for(int i=1;i<n;i++)
scanf("%d",×[i]);//读入两个站之间的时间消耗
/*
关于下面的has_train表更新的边界问题:
1.1站时不需要知道是否有车向左开
2.n站时不需要知道是否有车向右开
3.有车的定义:当前时刻该站有车次,且乘坐至下一站不会超时
*/
scanf("%d",&m1);//发车次数
for(int i=1;i<=m1;i++)
{
scanf("%d",&to[i]);
//更新has_train表
temp=to[i];//发车时刻,即车到达1站的时刻
for(int j=1;j<n && temp<=t;j++){
//车还没有到达终点站,且还没有超时
has_train[temp][j][0]=1;
temp+=times[j];//车开向下一站
}
}
//读取从n站发车的
scanf("%d",&m2);
for(int i=1;i<=m2;i++)
{
scanf("%d",&back[i]);
//更新has_train表
temp=back[i];//发车时刻,即车到达n站的时刻
for(int j=n-1;j>0 && temp<=t;j--){
//车还没有到1站,且还没超时
has_train[temp][j+1][1]=1;
temp+=times[j];
}
}
//dp[i][j]表示时刻i到达了j站还需要等待的时间
dp[t][n]=0;//不需要继续等了
for(int i=1;i<n;i++)//时刻t时,不在n站,说明已经不能完成任务了,即还需要等待INF
dp[t][i]=INF;
for(int i=t-1;i>=0;i--)
for(int j=1;j<=n;j++)
{
/*
一共有3种状态转移
1.在前1时刻已经到达了j站,那么就是之前时刻+1
2.是从j-1站坐车过来
3.是从j+1站坐车过来
所以应该取:
等待 和 乘上开往下一站的车 和乘上开往前一站的车 的最小值
*/
//填表法
//此处相当于初始化dp[i][j],是否能够通过等待完成任务
dp[i][j]=dp[i+1][j]+1;//当j站在i+1~T时刻均不能到达n点时,dp[i][j]是INF
//不是n站 && 有向右开的车 && 到下一站不会超时
if(j<n && has_train[i][j][0] && times[j]+i<=t)
dp[i][j]=min(dp[i][j],dp[i+times[j]][j+1]);//是否能通过前往下一站完成任务
//不是1站 && 有向右左开的车 && 到下一站不会超时
if(j>1 && has_train[i][j][1] && times[j-1]+i<=t)
dp[i][j]=min(dp[i][j],dp[i+times[j-1]][j-1]);//是否能够通过前往上一站完成任务
}
printf("Case Number %d: ",++kase);
if(dp[0][1]<INF)
printf("%d",dp[0][1]);
else
printf("impossible");
printf("\n");
}
return 0;
}
#大佬