Teleporter Setting(最短路,思维)
题意
给定一个\(N\)个点\(M\)条边的无向图,每条边用\((u_i, v_i)\)来表示,边权为\(1\)。
其中一些边是未定的,如:\((u_i, 0)\)表示一个点是\(u_i\),另一个点未定。
对于\(i = 1, 2, \dots, N\),问:当未定边的另一个点全都是\(i\)时,从\(1\)到\(N\)的最短距离是多少?
题目链接:https://atcoder.jp/contests/abc257/tasks/abc257_f
数据范围
\(2 \leq N \leq 3 \times 10^5\)
\(1 \leq M \leq 3 \times 10^5\)
思路
将\(0\)号点作为额外的点。当\(i = k\)时,问题转化为在\(0\)和\(k\)之间加一条边权为\(0\)的边,求\(1\)到\(N\)的最短路。
如果不使用加的这条边,那么答案为\(dist_{1,N}\)。如果使用这条边,那么必然经过\(0\)和\(k\)两个点,因此答案为\(\min (dist_{1, 0} + dist_{k, N}, dist_{1, k} + dist_{0, N})\)。
因此分别以\(1\)和\(N\)为起点,跑BFS即可。
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 300010, M = 2 * N;
int n, m;
int h[N], e[M], ne[M], idx;
int dist1[N], dist2[N];
void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
void bfs(int dist[], int u)
{
queue<int> que;
que.push(u);
for(int i = 0; i <= n; i ++) dist[i] = 1e9;
dist[u] = 0;
while(que.size()) {
int t = que.front();
que.pop();
for(int i = h[t]; ~i; i = ne[i]) {
int j = e[i];
if(dist[j] > dist[t] + 1) {
dist[j] = dist[t] + 1;
que.push(j);
}
}
}
}
int main()
{
scanf("%d%d", &n, &m);
memset(h, -1, sizeof h);
for(int i = 0; i < m; i ++) {
int a, b;
scanf("%d%d", &a, &b);
add(a, b), add(b, a);
}
bfs(dist1, 1), bfs(dist2, n);
for(int i = 1; i <= n; i ++) {
int ans = min(dist1[n], min(dist1[0] + dist2[i], dist1[i] + dist2[0]));
if(ans >= 1e9) ans = -1;
printf("%d ", ans);
}
printf("\n");
return 0;
}