欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

HDU1599 floyd最小环(无向图)问题

程序员文章站 2022-04-06 20:20:46
...

题目:杭州有N个景区,景区之间有一些双向的路来连接,现在8600想找一条旅游路线,这个路线从A点出发并且最后回到A点,假设经过的路线为V1,V2,…VK,V1,那么必须满足K>2,就是说至除了出发点以外至少要经过2个其他不同的景区,而且不能重复经过同一个景区。现在8600需要你帮他找一条这样的路线,并且花费越少越好。
Input
第一行是2个整数N和M(N <= 100, M <= 1000),代表景区的个数和道路的条数。
接下来的M行里,每行包括3个整数a,b,c.代表a和b之间有一条通路,并且需要花费c元(c <= 100)。
Output
对于每个测试实例,如果能找到这样一条路线的话,输出花费的最小值。如果找不到的话,输出"It’s impossible.".

解析

我们先来简单解释一下floyd算法,时间复杂度为O(n^3)
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
有一个起点i,一个终点j,然后通过 中转点k来不断取小求得最短路径,
然后将数值存贮在dis数组(邻接矩阵)中。

重头戏
如何求最小环(无向图),首先无向图的环最少得有三个顶点
我们就枚举i为起点,j为终点,k仍为中间节点
肯定有很多小伙伴跟我一样,
dis[i][j]+a[i][k]+a[k][j]
对上面这个式子很有疑惑
为啥不能是dis[i][j]+dis[i][k]+dis[k][j] 呢?
大家可以看下图,
如果用了dis[i][j]+dis[i][k]+dis[k][j]
k=2时,此时dis[1][3]已经从inf松弛为1+1=2的距离
结果是一个不成环的无向图输出的ans值却为4,很明显是的。
HDU1599 floyd最小环(无向图)问题
然后来看一下这个式子dis[i][j]+a[i][k]+a[k][j]
这里a数组存的是最初始的邻接矩阵,表示边权
所以要算一个最小环的话,我们就枚举一个中间点k,然后模拟一波
ans=min(ans,i到j的距离+边i到k的距离+边j到k的距离)
HDU1599 floyd最小环(无向图)问题

具体代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3+10;
const int inf=0x3f3f3f;
int a[maxn][maxn],dis[maxn][maxn];
int main()
{
	int n,m;
	while(scanf("%d %d",&n,&m)!=EOF)
	{
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				a[i][j]=a[j][i]=dis[i][j]=dis[j][i]=inf;
		while(m--)
		{
			int u,v,w;
			scanf("%d%d%d",&u,&v,&w);
			if(w<dis[u][v])
				a[u][v]=a[v][u]=dis[u][v]=dis[v][u]=w;
		}
		int ans=inf;
		for(int k=1;k<=n;k++)
		{
			for(int i=1;i<k;i++)
				for(int j=i+1;j<k;j++)//这里得是i+1,防止重复
					ans=min(ans,dis[i][j]+a[i][k]+a[k][j]);
			for(int i=1;i<=n;i++)
				for(int j=1;j<=n;j++)
					dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
		}
		if(ans==inf)puts("It's impossible.");
		else printf("%d\n",ans);
	}
	return 0;
}