P6464
题目:P6464
大意就是给定一张无向联通图,在两个节点间建立距离为0的传送门,求建完门后各点最短距离和的最小值。
首先我们能想到O(n5)的暴力,就是在枚举两个建传送门的点l,r的基础上跑floyd(由于n<=100,很自然就能想到n3的floyd)
此时得分已经很高了(我当时是80分),但是怎么能得100分呢?
考虑到n^4次方就能AC掉这个题,所以我们可以进行亿点点优化:
仔细思考后就能得出,当l,r两点建传送门后,对于点对(i,j),很显然要更新之前的最短路,只有可能是把l或r作为了中间节点。那这样floyd时间复杂度降到了n2,时间复杂度也就到了O(n4)。
代码:
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=520;
const int M=5217;
const int inf=0x3f3f3f3f;
int n,m,d[N][N],f[N][N],ans=inf,sum;
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){//初始化
for(int j=1;j<=i;j++){
if(i==j){
d[i][j]=0;
}
else{
d[i][j]=d[j][i]=inf;
}
}
}
for(int i=1;i<=m;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
d[u][v]=d[v][u]=w;
}
for(int k=1;k<=n;k++){//先求不安传送门的距离
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(d[i][j]>d[i][k]+d[k][j]){
d[i][j]=d[i][k]+d[k][j];
}
}
}
}
for(int l=1;l<=n;l++){//枚举传送门安哪里
for(int r=l+1;r<=n;r++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
f[i][j]=d[i][j];
}
}
f[l][r]=f[r][l]=0;
//经过l节点可能出现的最短路
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(f[i][j]>f[i][l]+f[l][j]){
f[i][j]=f[i][l]+f[l][j];
}
}
}
//经过r节点可能出现的最短路
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(f[i][j]>f[i][r]+f[r][j]){
f[i][j]=f[i][r]+f[r][j];
}
}
}
//统计当前答案并求最小
sum=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=i;j++){
sum+=f[i][j];
}
}
ans=min(ans,sum);
f[l][r]=f[r][l]=d[l][r];//回溯(?)
}
}
printf("%d",ans);
return 0;
}

浙公网安备 33010602011771号