P6464 [传智杯 #2 决赛] 传送门(绿色 普及+/提高)
graph, 最短路, Floyd算法, https://www.luogu.com.cn/problem/P6464
传智专修学院里有
为了使交通更为顺畅,校方决定在两个教学楼里增设一对传送门。传送门可以将这对教学楼的距离直接缩短为 0。利用传送门,某些教学楼之间的最短路的距离就变短了。
由于预算有限,学校里只能安装一对传送门。但是校长希望尽可能方便学生,使任意两点之间的最短路长度的总和最小。当然啦,从
输入格式
输入第 1 行两个正整数
接下来
输出格式
输出一行,在最优方案下的任意点对的最短道路之和。
输入输出样例 #1
输入 #1
4 5
1 2 3
1 3 6
2 3 4
2 4 7
3 4 2输出 #1
14说明/提示

样例如图。当在 1 和 4 号教学楼架设一对传送门时,1 → 2 的最短路是 3,1 → 3 的最短路是 0+2,1 → 4 的最短路是 0,2 → 3 的最短路是 4,2 → 4 的最短路是 3+0,3 → 4 的最短路是 2,最短路之和是 14,是最佳方案。
下面是本题的 0-indexed 双重循环优化及 Floyd-Warshall 算法的 Python 实现。
解题思路
多源最短路计算: 由于
,可以先使用 Floyd-Warshall 算法求出任意两点之间的初始最短距离,时间复杂度为 。 枚举传送门位置: 一共有
种不同的传送门放置方案。可以枚举这一对传送门所在的教学楼 。 计算新的最短路之和: 假设在
和 之间设立了传送门,则它们之间的距离变为了 。对于任意两个点 和 ,它们之间新的最短距离 只有以下三种可能: - 不通过传送门:距离为
。 - 通过传送门(从
到 ):距离为 。 - 通过传送门(从
到 ):距离为 。
因此,新的最短距离为:
通过遍历所有的点对
算出它们的新的最短路径之和。由于 ,整体计算量约为 次操作。在 Python 中,通过局部变量缓存和底层的比较优化,可以保证程序高效运行。 - 不通过传送门:距离为
Python 3 实现
import sys
def solve():
# 快速读入所有数据
input_data = sys.stdin.read().split()
if not input_data:
return
n = int(input_data[0])
m = int(input_data[1])
# 初始化二维数组 d,d[i][j] 表示点 i 到点 j 的最短距离
INF = 10**9
d = [[INF] * n for _ in range(n)]
# 每个点到它本身的距离为 0
for i in range(n):
d[i][i] = 0
# 读取输入的边并更新图的邻接矩阵(考虑可能有重边,取较小值)
idx = 2
for _ in range(m):
u = int(input_data[idx]) - 1
v = int(input_data[idx+1]) - 1
w = int(input_data[idx+2])
idx += 3
if w < d[u][v]:
d[u][v] = w
d[v][u] = w
# 标准 Floyd-Warshall 算法计算任意两点间的最短路径
for k in range(n):
for i in range(n):
for j in range(n):
if d[i][k] + d[k][j] < d[i][j]:
d[i][j] = d[i][k] + d[k][j]
ans = INF
# 枚举建立传送门的两个教学楼 u 和 v (u < v)
for u in range(n):
for v in range(u + 1, n):
current_sum = 0
# 计算在 u 和 v 之间建立传送门后,所有教学楼对之间的最短距离之和
for i in range(n):
for j in range(i + 1, n):
# 两点间新的最短距离只有以下三种可能:
# 1. 不走传送门:d[i][j]
# 2. 走传送门(由 u 到 v):d[i][u] + d[v][j]
# 3. 走传送门(由 v 到 u):d[i][v] + d[u][j]
new_dist = min(d[i][j], d[i][u] + d[v][j], d[i][v] + d[u][j])
current_sum += new_dist
# 记录所有方案中的最小值
if current_sum < ans:
ans = current_sum
print(ans)
if __name__ == '__main__':
solve()复杂度分析
- 时间复杂度:
- Floyd-Warshall 算法:
。 - 枚举方案并求和:共有
种方案,每次求和需要 的时间。整体时间复杂度为 。在 的数据规模下,最内层循环执行次数约 次,优化后的 Python 代码能在规定时间内完成评测。如果使用 PyPy 运行,效率会更高。
- Floyd-Warshall 算法:
- 空间复杂度:
,用于存储任意两点间距离的二维数组。