题目链接
翻译
注意是有向图,不然这题读起来会觉得题目很奇怪。。
题解
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;
}