26.城市裏的間諜 (UVa1025)

某城市的地鐵是線性的,有n2n50n(2≤n≤50)個車站,從左到右編號爲1n1~n。有M1M1輛列車從第1站開始往右開,還有M2M_2輛列車從第nn站開始往左開。在時刻00,Mario從第1站出發,目的是在時刻T0T200T(0≤T≤200)會見車站nn的一個間諜。在車站等車時容易被抓,所以她決定儘量躲在開動的火車上,讓在車站等待的總時間儘量短。列車靠站停車時間忽略不計,且Mario身手敏捷,即使兩輛方向不同的列車在同一時間靠站,Mario也能完成換乘。輸入第1行爲n,第2行爲TT,第3行有n1n-1個整數t1,t2,,tn11ti70t_1 , t_2 ,…, t _{n-1}(1≤t_i ≤70),其中tit_i表示地鐵從車站i到i+1的行駛時間(兩個方向一樣)。第4行爲M11M150M1(1≤M_1≤50),即從第1站出發向右開的列車數目。第5行包含M1M1個整數d1,d2,,dM10di250didi1d_1 , d_2 ,…, d_M1 (0≤d_i ≤250,d_i<d_i +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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章