【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;
}

posted @ 2021-01-11 20:51  AWCXV  阅读(149)  评论(0编辑  收藏  举报