洛谷 P6464 [传智杯 #2 决赛] 传送门
通过便利每两个点之间的传送门,再便利一次其他点与传送点的路长度,没路的情况是最大值不会考虑,有路就取经过传送门和原本最短路的最小值
点击查看代码
/* 台州第一深情 */
#include <bits/stdc++.h>
using namespace std;
using i64 = long;
using ll = long long;
typedef pair<int, int> PII;
const int N = 105 + 5;
const int M = 1e6;
ll a[N][N], b[M];
int n, m;
void build()
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (i == j)
{
a[i][j] = 0;//自己与自己的距离是0
}
else
{
a[i][j] = 1e7;//模板,根据题目定义最大值,因为还未进行floyd操作,所以都定位最大值
}
}
}
}
void floyd()
{//为何tiao点在最上面,因为每个点都可以是tiao点,就相当于暴力查找一边所有点通过tiao点到达另一个点的情况
for (int tiao = 1; tiao <= n; tiao++)//跳点,就是其他点可以通过这个点到达另一个点,就算from或to==tiao也没事,因为自己到本身的点是0,不会影响结果,
{
for (int from = 1; from <= n; from++)//枚举出发点
{
for (int to = 1; to <= n; to++)//目标点
{
a[from][to] = min(a[from][tiao] + a[tiao][to], a[from][to]);//a[from][tiao]就是从出发点到跳点距离,a[tiao][to]就是tiao点到目标点距离,再与他本身a[from][to]判断,取最小值
}
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
build();
for (int i = 1; i <= m; i++)
{
int from, to, w;
cin >> from >> to >> w;
a[from][to] = w;
a[to][from] = w;//无向图,存双边
}
ll ans = INT_MAX;
floyd();//先确定正常情况下的最小值
for (int i = 1; i < n; i++)
{
for (int j = i + 1; j <= n; j++)//i,j是假设从哪个点到哪个点有传送门
{
ll p = 0;
for (int i1 = 1; i1 < n; i1++)//每确定一个传送门都进行一次floyd,便利查找最小值
{
for (int j1 = i1 + 1; j1 <= n; j1++)
{
if (i1 != i || j1 != j)
{
p += min(a[i1][j1], min(a[i1][i] + a[j][j1], a[i1][j] + a[i][j1]));//便利每个点与传送点是否有路,如果有的话就判断一下经过传送门到目标点是不是会更短,将传送门当成跳点
}
}
}
ans = min(ans, p);//取小
}
}
cout << ans << "\n";
return 0;
}