Floyd 后枚举传送门端点,逐点对比较原路和两个传送方向。
OJ: luogu
题目 ID: P6464
难度:普及+/提高-
标签:Floyd枚举全源最短路python
日期: 2026-07-17 03:00
题意
选择两个点安装距离为 0 的双向传送门,最小化所有无序点对最短路之和。
思路
先 Floyd 得到原图任意两点距离。固定传送门 a,b 后,点对 x,y 的新距离是原距离、x-a-b-y、x-b-a-y 三者最小值;枚举端点和点对求总和。
Python 知识
- 二维列表直接保存百点规模距离矩阵。
- 内层缓存行引用减少多重索引。
min接收三个候选,和公式一一对应。
代码
python
import sys
input = sys.stdin.buffer.readline
n, edges = map(int, input().split())
infinity = 10**18
distance = [[infinity] * n for _ in range(n)]
for node in range(n):
distance[node][node] = 0
for _ in range(edges):
u, v, weight = map(int, input().split())
u -= 1
v -= 1
distance[u][v] = distance[v][u] = weight
for middle in range(n):
through = distance[middle]
for start in range(n):
row = distance[start]
base = row[middle]
for end in range(n):
row[end] = min(row[end], base + through[end])
answer = infinity
for first in range(n):
from_first = distance[first]
for second in range(first + 1, n):
from_second = distance[second]
total = 0
for x in range(n):
row = distance[x]
for y in range(x + 1, n):
total += min(row[y], row[first] + from_second[y], row[second] + from_first[y])
answer = min(answer, total)
print(answer)原有 C++ 版本仍保留:
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-07-17 01:40
* update_at: 2026-07-17 01:40
*/
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
return 0;
}复杂度
Floyd O(n^3),枚举约 O(n^4),但 n<=100,实际约四分之一点对组合。
总结
加一条特殊边后,任意新最短路至多使用一次这条边,可直接枚举两个方向。
