1. 程式人生 > 實用技巧 >【Codeforces Round #693 (Div. 3) G】Moving to the Capital

【Codeforces Round #693 (Div. 3) G】Moving to the Capital

題目連結

連結

翻譯

注意是有向圖,不然這題讀起來會覺得題目很奇怪。。

題解

bfs 求最短路 d[1..n],然後對於 \(d_i<d_j\) 的邊連實線,否則連虛線。

就可以做 dp 了,對於實線 dp[x] = min(dp[x],dp[y]),對於虛線 dp[x] = min(dp[x],d[y])

虛線只能走一次嘛。然後實線還能順著往下走。妥妥的記憶化,當然不要忘了待在原地不動的情況,對應 \(dp[x]=min(dp[x],d[x])\)

程式碼

#include <bits/stdc++.h>
#define LL long long
using namespace std;

const int N = 2e5;
const LL MOD = 1e9 + 7;
const int K = 5000;

int n, m, d[N+10],dp[N+10];
vector<int> g[3][N + 10];
queue<int> dl;

void bfs() {
	for (int i = 1; i <= n; i++) {
		d[i] = n + 1;
	}
	d[1] = 0;
	dl.push(1);
	while (!dl.empty()) {
		int x = dl.front();
		dl.pop();
		int len = g[0][x].size();
		for (int y : g[0][x]) {
			if (d[y] == n + 1) {
				d[y] = d[x] + 1;
				dl.push(y);
			}
		}
	}
}

int dfs(int x) {
	if (dp[x] != n + 1) {
		return dp[x];
	}
	//實線可以任意走。
	for (int y : g[1][x]) {
		dp[x] = min(dp[x], dfs(y));
	}
	//虛線只能走一次。
	for (int y : g[2][x]) {
		dp[x] = min(dp[x], d[y]);
	}
	//待在原地
	dp[x] = min(dp[x], d[x]);
	return dp[x];
}

int main() {
	#ifdef LOCAL_DEFINE
		freopen("in.txt", "r", stdin);
	#endif
	ios::sync_with_stdio(0), cin.tie(0);
	int T;
	cin >> T;
	while (T--) {
		cin >> n >> m;
		for (int i = 1; i <= n; i++) {
			for (int j = 0; j < 3; j++) {
				g[j][i].clear();
			}
		}
		for (int i = 1; i <= m; i++) {
			int x, y;
			cin >> x >> y;
			g[0][x].push_back(y);
		}
		bfs();
		for (int x = 1; x <= n; x++) {
			for (int y : g[0][x]) {
				if (d[y] > d[x]) {
					g[1][x].push_back(y);
				}
				else {
					//虛線
					g[2][x].push_back(y);
				}
			}
		}
		for (int i = 1; i <= n; i++) {
			dp[i] = n + 1;
		}
		for (int i = 1; i <= n; i++) {
			if (dp[i] == n + 1) {
				dp[i] = dfs(i);
			}
		}
		for (int i = 1; i <= n; i++) {
			cout << dp[i] << " ";
		}
		cout << endl;
	}
	return 0;
}