您的位置:首页 > 其它

城市里的间谍(A Spy in the Metro UVa 1025)

2018-01-29 17:13 323 查看
没错,这里有部分是转发的,因为其中一些注解让我理解了这题的过程。非常感激

http://blog.csdn.net/NOIAu/article/details/71517440

题意:

某城市的地铁是线性的,有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。

思路:

这个题主要受时间和车站控制,所以每一个车站算是一个状态,每一个状态都有三种决策,这里先说出来转移方程吧:

(1) d(i,j)=d(i+1,j)+1;

(2) d(i,j)=min(d(i,j),d(i+t[j],j+1));

(3) d(i,j)=min(d(i,j),d(i+t[j-1],j-1));

可能没法理解为什么是这么比较的,为什么后一个和当前的对比,因为这个题是逆推。

这里我贴上大佬的解释:

这道题一看要问最少需要等待多少时间,自然会想到用dp,那么怎么来处理这个问题呢?我们可以用dp[i][j]来表示时刻i,你现在身处第j个站,最少还需要等待多长时间,我们所知的是,在T时刻,你人一定需要在第n个车站去完成间谍任务,所以dp[T]
=0;可以由这个位置来进行反推,比如我在时刻T-1可以仍然位于车站n或者说如果有往左开的车我就有选择往左坐车的可能;

那么我们对于一个dp[i][j]进行状态转移,有三种转移方式:

决策一:

是我呆在原地不动,这个时候需要等的时间是由dp[i+1][j]转移而来,需要在dp[i+1][j]的基础上+1;因为我在j+1的时候的最优等待值的基础上,等待一个时间(时间从后往前逆推,注意dp数组表示的是最少还需要等待多少时间)

dp[i][j]=dp[i+1][j]+1;


决策二:

往右移动,如果往右有车的话

那么dp[i][j]就需要从dp[i+t[j]][j+1]转移过来

dp[i+t[j]][j+1]表示的是时刻i+t[j]的时候(相当于是往右到下一站j+1站的时候的最优值),由于是逆推的,所以dp[i+t[j]][j+1]的值先于dp[i][j]计算出,所以dp转移合理

dp[i][j]=min(dp[i][j],dp[i+t[j]][j+1]);


决策三:

往左移动,如果往左有车的话

那么dp[i][j]就需要从dp[i+t[j-1]][j-1]转移过来,原理和上面一样,往左需要花t[j-1]的时间,i+t[j-1]的时刻,位置在左一站的j-1站时的最优值,由于循环里先循环的是i,而且是逆向循环,所以dp[i+t[j-1]][j-1]的值也先已经计算得出,所以dp转移合理

dp[i][j]=min(dp[i][j],dp[i+t[j-1]][j-1]);


那么如何判定在某一个时刻有没有车往左或者往右已进行dp转移呢,我们可以先进行预处理,用一个has_a _train[i][j][2]数组来存储,其中has_a _train[i][j][0]表示i时刻在j车站,有没有一辆向左开的地铁,has_a _train[i][j][1]则表示i时刻在j车站,有没有一辆向右开的地铁 .

代码:

#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
#define INF 9999999
#define maxn 250+50
int T, n, m1, m2;
int t[maxn], a[maxn], b[maxn];
int has_train[maxn][maxn][2];
int dp[maxn][maxn];
int main(void) {
int kase = 0;
while (cin >> n&&n) {
memset(has_train, 0, sizeof(has_train));
cin >> T;
t[0] = t
= 0;
for (int i = 1; i <= n-1; i++) {
cin >> t[i];
}
cin >> m1;
for (int i = 1; i <= m1; i++) {
cin >> a[i];
int sum = a[i];
for (int j = 0; j <= n-1; j++) {
sum += t[j];
has_train[sum][j + 1][0] = 1;
}
}
cin >> m2;
for (int i = 1; i <= m2; i++) {
cin >> b[i];
int sum = b[i];
for (int j = n; j >=1; j--) {
sum += t[j];
has_train[sum][j][1] = 1;
}
}
for (int i = 1; i <= n-1; i++) {
dp[T][i] = INF;
}
dp[T]
= 0;
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]);
}
cout << "case number " << ++kase << ": ";
if (dp[0][1] >= INF)cout << "impossible" << endl;
else cout << dp[0][1] << endl;
}
system("pause");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: