给定一个 n 个点 m 条边的无向连通图。
图中所有点的编号为 1∼n。
图中不含重边和自环。
指定图中的 k 个点为特殊点。
现在,你必须选择两个特殊点,并在这两个点之间增加一条边。
所选两点之间允许原本就存在边。
我们希望,在增边操作完成以后,点 1 到点 n 的最短距离尽可能大。
输出这个最短距离的最大可能值。
注意,图中所有边(包括新增边)的边长均为 1。
输入格式
第一行包含三个整数 n,m,k。
第二行包含 k 个整数 a1,a2,…,ak,表示 k 个特殊点的编号,ai 之间两两不同。
接下来 m 行,每行包含两个整数 x,y,表示点 x 和点 y 之间存在一条边。
输出格式
一个整数,表示最短距离的最大可能值。
数据范围
前六个测试点满足 2≤n≤100。
所有测试点满足 2≤n≤2×10^5,n−1≤m≤2×10^5,2≤k≤n,1≤ai≤n,1≤x,y≤n。
输入样例1:
5 5 3
1 3 5
1 2
2 3
3 4
3 5
2 4
输出样例1:
3
输入样例2:
5 4 2
2 4
1 2
2 3
3 4
4 5
输出样例2:
3
【分析】
算法:bfs
因为边的权值为1,所以使用bfs求最短路;
针对每个点,求出到1到所有点i的最短距离为dist1[i]、n到所有点i的最短距离dist2[i]
接着对两个选择点进行讨论。根据是否在最短路径上可以分为两类:
1. 两个点不在最短路上面,答案还是dist1[n]
2. 两个点在最短路上,设两点为x,y,那么就有如下两种情况:
① 最短路径可能是1—>x, x—>y, y—>n。答案:dist1[x]+1+dist2[y]
② 最短路径可能是1—>y, y—>x, x—>n。答案:dist1[y]+1+dist2[x]
参考代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5, M = 2 * N;
struct node{
int to,next;
}e[M];
int h[N], cnt=0;
int n, m, k, q[N], tt, hh, p[N], dis1[N], dis2[N];
void add(int a, int b){
e[++cnt].to = b, e[cnt].next = h[a], h[a] = cnt;
}
void bfs(int st, int dis[]) {
memset(dis, 0x3f, 4*N);
dis[st] = 0;
queue<int> q;
q.push(st);
while (!q.empty()) {
int t = q.front();
q.pop();
for (int i = h[t]; i; i = e[i].next) {
int j = e[i].to;
if (dis[j] > dis[t] + 1) {
dis[j] = dis[t] + 1;
q.push(j);
}
}
}
}
bool cmp(int a, int b) {
return dis1[a] + dis2[b] < dis1[b] + dis2[a];
}
int main() {
scanf("%d%d%d", &n, &m, &k);
for (int i = 0; i < k; i++) scanf("%d", &p[i]);
int a, b;
while (m--) {
scanf("%d%d", &a, &b);
add(a, b), add(b, a);
}
bfs(1, dis1);
bfs(n, dis2);
sort(p, p + k, cmp);
int res = 0, maxv = dis1[p[0]]; //res记录最大距离
for (int i = 1; i < k; i++) {
res = max(res, maxv + dis2[p[i]] + 1);
maxv = max(maxv, dis1[p[i]]);
}
printf("%d", min(res, dis1[n]));
return 0;
}