某城市的地铁是线性的,有 n ( 2 ≤ n ≤ 50 ) n(2≤n≤50) n(2≤n≤50)个车站,从左到右编号为 1 ~ n 1~n 1~n。有 M 1 M1 M1辆列车从第1站开始往右开,还有 M 2 M_2 M2辆列车从第 n n n站开始往左开。在时刻 0 0 0,Mario从第1站出发,目的是在时刻 T ( 0 ≤ T ≤ 200 ) T(0≤T≤200) T(0≤T≤200)会见车站 n n n的一个间谍。在车站等车时容易被抓,所以她决定尽量躲在开动的火车上,让在车站等待的总时间尽量短。列车靠站停车时间忽略不计,且Mario身手敏捷,即使两辆方向不同的列车在同一时间靠站,Mario也能完成换乘。输入第1行为n,第2行为 T T T,第3行有 n - 1 n-1 n-1个整数 t 1 , t 2 , … , t n - 1 ( 1 ≤ t i ≤ 70 ) t_1 , t_2 ,…, t _{n-1}(1≤t_i ≤70) t1,t2,…,tn-1(1≤ti≤70),其中 t i t_i ti表示地铁从车站i到i+1的行驶时间(两个方向一样)。第4行为 M 1 ( 1 ≤ M 1 ≤ 50 ) M1(1≤M_1≤50) M1(1≤M1≤50),即从第1站出发向右开的列车数目。第5行包含 M 1 M1 M1个整数 d 1 , d 2 , … , d M 1 ( 0 ≤ d i ≤ 250 , d i < d i + 1 ) d_1 , d_2 ,…, d_M1 (0≤d_i ≤250,d_i<d_i +1) d1,d2,…,dM1(0≤di≤250,di<di+1),即各列车的出发时间。第6、7行描述从第n站出发向左开的列车,格式同第4、5行。输出仅包含一行,即最少等待时间。无解输出impossible。
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 50 + 5;
const int maxt = 200 + 5;
const int INF = 1000000000;
// has_train[t][i][0]表示时刻t,在车站i是否有往右开的火车
int t[maxn], has_train[maxt][maxn][2];
int dp[maxt][maxn];
int main() {
int kase = 0, n, T; // T时刻在车站n会面
while (1) {
cout << "会面(总共)车站个数n:";
cin >> n;
if (n == 0) break;
cout << "会面时刻T:";
cin >> T;
int M1, M2, d;
cout << "车站之间的行驶时间: ";
for (int i = 1; i <= n - 1; i++) cin >> t[i]; // 预处理,计算has_train数组
memset(has_train, 0, sizeof(has_train));
cout << "右向行驶的车辆数: ";
cin >> M1;
cout << "右向行驶的车辆出发时间: ";
while (M1--) {
cin >> d;
for (int j = 1; j <= n - 1; j++) {
if (d <= T) has_train[d][j][0] = 1;
d += t[j];
}
}
cout << "左向行驶的车辆数: ";
cin >> M2;
cout << "左向行驶的车辆出发时间: ";
while (M2--) {
cin >> d;
for (int j = n - 1; j >= 1; j--) {
if (d <= T) has_train[d][j + 1][1] = 1;
d += t[j];
}
}
// DP主过程
// dp是i时刻在j车站期望最少等待时间
for (int i = 1; i <= n - 1; i++) dp[T][i] = INF;
dp[T][n] = 0; // 在T时刻n车站会面,所以dp[T][n]期望最少等待时间为0(边界条件)
for (int i = T - 1; i >= 0; i--) // 会面时间向前推理
for (int j = 1; j <= n; j++) {
dp[i][j] = dp[i + 1][j] + 1;
// 假设选择等待一个分钟:期望最少等待时间为下一时刻还在该车站的期望最少等待时间dp[i + 1][j]加1分钟
if (j < n && has_train[i][j][0] && i + t[j] <= T) //选择向右并到达下一车站时刻为i + t[j]不能错过会面时刻T
dp[i][j] = min(dp[i][j], dp[i + t[j]][j + 1]);
// 比较等待一分钟和选择向右期望最少等待时间(下一时刻为:当前时刻加该车站与下一车站花费时间i + t[j],下一个车站:j+1)
if (j > 1 && has_train[i][j][1] && i + t[j - 1] <= T)//选择向左并到达上一车站时刻为i + t[j]不能错过会面时刻T
dp[i][j] = min(dp[i][j], dp[i + t[j - 1]][j - 1]);
// 比较等待一分钟和选择向左期望最少等待时间(下一时刻为:当前时刻加该车站与上一车站花费时间i + t[j-1],上一个车站:j-1)
}
// 输出
cout << "Case Number " << ++kase << ": ";
if (dp[0][1] >= INF) cout << "impossible\n";
else cout << dp[0][1] << "\n"; // 在第一个车站时刻0的期望最少等待时间
}
return 0;
}