题目描述
P6464传送门
传智专修学院里有 n 栋教学楼,有 m 条双向通行道路连接这些教学楼,不存在重边和自环。每条道路都有一定的长度,而且所有教学楼之间都可以直接或者间接的通过道路到达。我们可以很容易的求出这些教学楼之间的最短路。
为了使交通更为顺畅,校方决定在两个教学楼里增设一对传送门。传送门可以将这对教学楼的距离直接缩短为 0。利用传送门,某些教学楼之间的最短路的距离就变短了。
由于预算有限,学校里只能安装一对传送门。但是校长希望尽可能方便学生,使任意两点之间的最短路长度的总和最小。当然啦,从 x 教学楼到 y 教学楼的长度和从 y 教学楼到 x 教学楼的长度只需要统计一次就可以了。
输入格式
输入第 1 行两个正整数n,m(n≤100,m≤n(n−1)/2),代表教学楼和道路数量。
接下来 m 行,每行三个正整数xi,yi,wi(0<wi≤104),表示在教学楼 xi 和 yi 之间,有一条长度为 wi 的道路。
输出格式
输出一行,在最优方案下的任意点对的最短道路之和。
输入输出样例
输入 #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,是最佳方案。
分析:
这个题目所给的数据比较小又是最短路问题,可以联想到Floyd,由于在他想安装一个传送门来将所有点的距离和变得最小,那么可以想到的是在先对没有安装传送门时的最短路用Floyd找出来存放在数组 f 中然后一一枚举在每两个点之间安装传送门,在枚举的过程中如果我们用下面的代码那么就会面临超时警告。
ll floyd(){
for(int j=1;j<=n;j++)
for(int i=1;i<=n;i++)
for(int k=1;k<=n;k++)
g[i][k]=min(g[i][k],g[i][j]+g[j][k]);
ll res=0;
for(int i=1;i<=n;i++)
for(int k=1;k<i;k++)
res+=g[i][k];
return res;
}
因为n的范围是100如果这样的话时间复杂度为O(n^5)这样一定会超时的,那么要如何才能不超时呢?我们可以这样想,每次我们在某两个点(i,k)之间安装传送门,那么安装传送门只会影响与(i,k)这两个点相连的点的距离所以我们可以分别将 i,k作为中间点然后更改g这样时间复杂度就变成了O(n^4)代码如下:
ll floyd(int a,int b){
for(int i=1;i<=n;i++)
for(int k=1;k<=n;k++)
g[i][k]=min(g[i][k],g[i][a]+g[a][k]);
for(int i=1;i<=n;i++)
for(int k=1;k<=n;k++)
g[i][k]=min(g[i][k],g[i][b]+g[b][k]);
ll res=0;
for(int i=1;i<=n;i++)
for(int k=1;k<i;k++)
res+=g[i][k];
return res;
}
AC代码
#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define ll long long
using namespace std;
const int N=110;
int f[N][N],g[N][N];
int n,m;
ll floyd(int a,int b){
for(int i=1;i<=n;i++)
for(int k=1;k<=n;k++)
g[i][k]=min(g[i][k],g[i][a]+g[a][k]);
for(int i=1;i<=n;i++)
for(int k=1;k<=n;k++)
g[i][k]=min(g[i][k],g[i][b]+g[b][k]);
ll res=0;
for(int i=1;i<=n;i++)
for(int k=1;k<i;k++)
res+=g[i][k];
return res;
}
void init(){
for(int i=1;i<=n;i++)
for(int k=1;k<=n;k++)
g[i][k]=f[i][k];
}
int main()
{
IOS;
cin>>n>>m;
for(int j=1;j<=n;j++)
for(int i=1;i<=n;i++)
if(i==j)f[i][j]=0;
else f[i][j]=1e9;
for(int i=1;i<=m;i++){
int x,y,c;cin>>x>>y>>c;
f[y][x]=f[x][y]=min(f[x][y],c);
}
for(int j=1;j<=n;j++)
for(int i=1;i<=n;i++)
for(int k=1;k<=n;k++)
f[i][k]=min(f[i][k],f[i][j]+f[j][k]);
ll res=2e9;
for(int i=1;i<=n;i++){
for(int k=1;k<i;k++){
init();
g[k][i]=g[i][k]=0;
ll x=floyd(i,k);
res=min(res,x);
}
}
cout<<res;
return 0;
}