1. 问题描述:
给定一个 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
来源:https://www.acwing.com/problem/content/3800/
2. 思路分析:
分析题目可以知道如果不加边那么1号点到n号点的最短距离是确定的,因为所有的边权为1所以可以使用bfs求解最短距离,加边之后对最短距离有什么影响吗?我们可以分三种情况讨论:
- 1号点到n号点的最短路不经过特殊点a,b,所以最短距离是不变的
- 经过了特殊点a,b,最短距离为dist1[a] + dist2[b] + 1
- 经过了特殊点b,a,最短距离为dist1[b] + dist2[a] + 1
我们可以使用bfs预处理出1号点到其余点的最短距离dist1和n号点到其余点的最短距离dist2,因为第二三种情况是加边之后的所以我们可以使得第二三种的最短距离最大,然后与第一种情况取一个min即可,对于第一种情况最短距离为dist1[n],所以问题就转换为了如何选取k个点中的两个点使得1号点到n号点的最短距离最大,我们可以先画画图:
可以发现我们在选取点的时候可以按照xi + xj最小的顺序来选择这样可以使得选择的顺序是确定的,然后枚举k个特殊点,在枚举点的时候维护dist1[x]的最大值,在k个点任取两个点的过程中选取一个最大值就是第二三种情况的最大值。
3. 代码如下:
import collections
from typing import List
class Solution:
# bfs求解start到其余点的最短距离
def bfs(self, start: int, dis: List[int], g: List[List[int]]):
# 注意collections.deque加入起点的时候需要在前面套一个列表
q = collections.deque([start])
# 将起点位置的距离置为0
dis[start] = 0
while q:
p = q.popleft()
for next in g[p]:
if dis[next] > dis[p] + 1:
dis[next] = dis[p] + 1
q.append(next)
def process(self):
n, m, k = map(int, input().split())
a = list(map(int, input().split()))
g = [list() for i in range(n + 10)]
for i in range(m):
x, y = map(int, input().split())
# 无向边, 所以需要建两个方向的边
g[x].append(y)
g[y].append(x)
INF = 10 ** 10
dist1, dist2 = [INF] * (n + 10), [INF] * (n + 10)
# 求解1号点到其余点的最短距离
self.bfs(1, dist1, g)
# 求解n号点到其余点的最短距离
self.bfs(n, dist2, g)
# 根据lambda表达式排序
a.sort(key=lambda x: dist1[x] - dist2[x])
res, x = 0, dist1[a[0]]
# 枚举所有可能的点对
for i in range(1, k):
res = max(res, dist2[a[i]] + x + 1)
# 更新1号点到a[i]号点的最大距离
x = max(x, dist1[a[i]])
return min(res, dist1[n])
if __name__ == '__main__':
print(Solution().process())