无向图最小环问题

分析

本题的 \(n\) 较小,用 Floyd 以 \(O(n^3)\) 的复杂度即可通过

我们首先来看 Floyd 的代码:

for(int k=1;k<=n;k++)
{
	for(int i=1;i<=n;i++)		
	{
		for(int j=1;j<=n;j++)
		{
			dp[i][j]=std::min(dp[i][j],dp[i][k]+dp[k][j]);
		}
	}
}

我们可以看到,第一层关于阶段 \(k\) 的枚举表示考虑了前 \(k-1\) 个点所求得的最短路,同时这前 \(k-1\) 个点及其路径均不包括 \(k\)

那么我们可以在第 \(k\) 个阶段更新最短路之前先处理得到通过前 \(k-1\) 个点所构成的最小环,该环即为两点间最短距离与 \(k\) 点的距离之和,不断更新答案即可

之后再进行最短路的更新

code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<math.h>
#include<vector>
#include<queue>
#define ll long long
using namespace std;

const ll maxn=110;
const ll maxm=5e3+10;
const ll inf=1e9+10;
ll n,m,ans=inf;
ll f[maxn][maxn],dp[maxn][maxn];

int main(void)
{
	scanf("%lld %lld",&n,&m);
	
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			if(i!=j) dp[i][j]=f[i][j]=inf;
		}
	}
	
	for(int i=1;i<=m;i++)
	{
		ll x,y,z;
		scanf("%lld %lld %lld",&x,&y,&z);
		
		f[x][y]=std::min(f[x][y],z);
		f[y][x]=std::min(f[y][x],z);
		dp[x][y]=std::min(dp[x][y],z);
		dp[y][x]=std::min(dp[y][x],z);
	}
	
	for(int k=1;k<=n;k++)
	{
		for(int i=1;i<k;i++)//注意这里要保证 i<k ,以保证为前 k 个点
		{
			for(int j=i+1;j<k;j++)// j 同理
			{
				ans=std::min(ans,dp[i][j]+f[i][k]+f[k][j]);
			}
		}
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=n;j++)	
			{
				dp[i][j]=std::min(dp[i][j],dp[i][k]+dp[k][j]);
				dp[j][i]=dp[i][j];
			}
		}
	}
	
	if(ans==inf) printf("No solution.\n");
	else
	{
		printf("%lld\n",ans);
	}
	
	return 0;
}
posted @ 2021-01-31 15:14  雾隐  阅读(117)  评论(0编辑  收藏  举报