HDU1599 floyd最小环(无向图)问题
题目:杭州有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,很明显是错的。
然后来看一下这个式子dis[i][j]+a[i][k]+a[k][j];
这里a数组存的是最初始的邻接矩阵,表示边权。
所以要算一个最小环的话,我们就枚举一个中间点k,然后模拟一波
ans=min(ans,i到j的距离+边i到k的距离+边j到k的距离)
具体代码
#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;
}