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;
}
posted @ 2025-07-07 15:46  qwqSW  阅读(11)  评论(0)    收藏  举报