題目描述
某城市地鐵是線性的,有n個車站,從左到右編号1-n。有M1輛列車從第1站開始往右開,還有M2輛列車從第n站開始往左開。在時刻0,Mario從第1站出發,目的在時刻T會見車站n的一個間諜。在車站等車時容易被抓,是以她決定盡量躲在開動的火車上,讓在車站等待的時間盡量短。列車靠站停車時間忽略不計,且Mario身手靈活,即時兩輛方向不同的列車在同一時間靠站,Mario也能完成換乘。
Input Data
輸入第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行。
Output Data
輸出僅包含一行,即最少等待時間。無解輸出impossible。
Input
4
55
5 10 15
4
0 5 10 20
4
0 5 10 15
4
18
1 2 3
5
0 3 6 10 12
6
0 3 5 7 12 15
2
30
20
1
20
7
1 3 5 7 11 13 17
Output
Case Number 1: 5
Case Number 2: 0
Case Number 3: impossible
——————————————分割の線————————————————
已知時間i,Mario停留在j站。不難發現Mario之前到達j站的路徑和時間與之後的決策并無關系,且決策僅與目前的時間和所處的車站有關。不妨用f[i][j]表示時刻i,Mario處于站台j時,最少還需要等待的時間。邊界為f[T][n]=0,f[T][i]=+∞;
存在三種決策:
- 就地等一分鐘
- 如果有車,搭乘向左開的車
- 如果有車,搭乘向右開的車
在主過程上,運用填表法:
for(int i=T-;i>=;i--)
{
for(int j=;j<=n;j++)
{
f[i][j]=f[i+][j]+;
if(j<n&&has_train[i][j][]&&i+t[j]<=T)
f[i][j]=min(f[i][j],f[i+t[j]][j+]);//right
if(j>&&has_train[i][j][]&&i+t[j-]<=T)
f[i][j]=min(f[i][j],f[i+t[j-]][j-]);//left
}
}
此處運用has_train[t][i][0]表示時刻i,在站台j是否有向右的火車。has_train[t][i][0]與其類似,但是是記錄是否有向左開的火車。
我在輸入時進行處理:
memset(has_train,,sizeof(has_train));
cin>>m1;
for(int i=;i<=m1;i++)
{
int sum;
scanf("%d",&sum);//讀入發車時間
for(int j=;j<=n;j++)
{
has_train[sum][j][]=;//記錄在時刻sum站台j,有一輛向右開的火車
sum+=t[j];//行駛到站台j+1的時間
}
}
cin>>m2;
for(int i=;i<=m2;i++)
{
int sum;
scanf("%d",&sum);//讀入發車時間
for(int j=n;j>=;j--)//由于是從右向左開,是以反向枚舉
{
has_train[sum][j][]=;//記錄在時刻sum站台j,有一輛向左開的火車
sum+=t[j-];//行駛到站台j-1的時間
}
}
完整過程如下:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define INF 0x11111111
int t[];
int f[][],has_train[][][];
int main()
{
int n,T,m1,m2,cnt=,sick=;
while(cin>>n&&n!=)
{
memset(t,,sizeof(t));
memset(has_train,,sizeof(has_train));
cnt++;
cin>>T;
for(int i=;i<n;i++)
scanf("%d",&t[i]);//讀入從i到i+1的行駛時間,用t[i]表示
cin>>m1;
for(int i=;i<=m1;i++)
{
int sum;
scanf("%d",&sum);//讀入發車時間
for(int j=;j<=n;j++)
{
has_train[sum][j][]=;//記錄在時刻sum站台j,有一輛向右開的火車
sum+=t[j];//行駛到站台j+1的時間
}
}
cin>>m2;
for(int i=;i<=m2;i++)
{
int sum;
scanf("%d",&sum);//讀入發車時間
for(int j=n;j>=;j--)//由于是從右向左開,是以反向枚舉
{
has_train[sum][j][]=;//記錄在時刻sum站台j,有一輛向左開的火車
sum+=t[j-];//行駛到站台j-1的時間
}
}
for(int i=;i<n;i++)
f[T][i]=INF;
f[T][n]=;//以上均為初始化
for(int i=T-;i>=;i--)
{
for(int j=;j<=n;j++)
{
f[i][j]=f[i+][j]+;
if(j<n&&has_train[i][j][]&&i+t[j]<=T)
f[i][j]=min(f[i][j],f[i+t[j]][j+]);//right
if(j>&&has_train[i][j][]&&i+t[j-]<=T)
f[i][j]=min(f[i][j],f[i+t[j-]][j-]);//left
}
}
printf("Case Number %d: ",cnt);
if(f[][]>=INF) printf("impossible\n");//隻有時刻0并從站台1出發,才合法
else printf("%d\n",f[][]);
}
return ;
}
狀态有O(nT)個,每個狀态最多隻有3個決策,是以總時間複雜度為O(nT).