26.城市里的间谍 (UVa1025)

本文介绍了一种基于动态规划的最优路径算法,用于解决某城市线性地铁线路中,Mario如何在规定时间内从第一站到达最后一站,同时在车站等待时间最短的问题。算法考虑了双向列车的运行情况,通过预处理列车运行状态,实现对每个车站和时间点的最优选择。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

某城市的地铁是线性的,有n(2≤n≤50)n(2≤n≤50)n2n50个车站,从左到右编号为1~n1~n1n。有M1M1M1辆列车从第1站开始往右开,还有M2M_2M2辆列车从第nnn站开始往左开。在时刻000,Mario从第1站出发,目的是在时刻T(0≤T≤200)T(0≤T≤200)T0T200会见车站nnn的一个间谍。在车站等车时容易被抓,所以她决定尽量躲在开动的火车上,让在车站等待的总时间尽量短。列车靠站停车时间忽略不计,且Mario身手敏捷,即使两辆方向不同的列车在同一时间靠站,Mario也能完成换乘。输入第1行为n,第2行为TTT,第3行有n-1n-1n1个整数t1,t2,…,tn-1(1≤ti≤70)t_1 , t_2 ,…, t _{n-1}(1≤t_i ≤70)t1,t2,,tn11ti70,其中tit_iti表示地铁从车站i到i+1的行驶时间(两个方向一样)。第4行为M1(1≤M1≤50)M1(1≤M_1≤50)M11M150,即从第1站出发向右开的列车数目。第5行包含M1M1M1个整数d1,d2,…,dM1(0≤di≤250,di<di+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、付费专栏及课程。

余额充值