26.城市里的间谍 (UVa1025)

某城市的地铁是线性的,有 n ( 2 ≤ n ≤ 50 ) n(2≤n≤50) n2n50个车站,从左到右编号为 1 ~ n 1~n 1n。有 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) T0T200会见车站 n n n的一个间谍。在车站等车时容易被抓,所以她决定尽量躲在开动的火车上,让在车站等待的总时间尽量短。列车靠站停车时间忽略不计,且Mario身手敏捷,即使两辆方向不同的列车在同一时间靠站,Mario也能完成换乘。输入第1行为n,第2行为 T T T,第3行有 n - 1 n-1 n1个整数 t 1 , t 2 , … , t n - 1 ( 1 ≤ t i ≤ 70 ) t_1 , t_2 ,…, t _{n-1}(1≤t_i ≤70) t1,t2,,tn11ti70,其中 t i t_i ti表示地铁从车站i到i+1的行驶时间(两个方向一样)。第4行为 M 1 ( 1 ≤ M 1 ≤ 50 ) M1(1≤M_1≤50) M11M150,即从第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,,dM10di250didi1,即各列车的出发时间。第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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值