什么是最小环?就是所有组成环的环,边权值最小的环,就是最小环。

我们由一道题,进入这个问题。

链接:hdu1599

find the mincost route

Time Limit: 1000/2000 MS (Java/Others) , Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 8189 , Accepted Submission(s): 3100

Problem Description
杭州有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.".

Sample Input
3 3
1 2 1
2 3 1
1 3 1

3 3
1 2 1
1 2 3
2 3 1

Sample Output
3
It’s impossible.

题意很简单,我们可以看出就是一个最小环寻找问题。

求最小环我们可以利用floyd来求,什么你还不会Floyd?(自己看书)

其实Floyd很简单,用四行代码就能解决。

for(int k=1;k<=n;k++)
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			g[i][j]=g[j][i]=min(g[i][j],g[i][k]+g[k][j]);

思路也十分简单,就是利用一个点k,看i,j之间的路径能否通过k点中转,使得i,j之间的路径变短。

这里我们探讨怎么利用floyd求最小环。

我们来分析下floyd的实现过程,当枚举顶点k之前我们已经求得了顶点为1 - k-1 的最短路,所以我们可以在跟新k之前枚举k之前的i和j的组合,我们可以知道dis[i][j]没有经过k点,所以我们就可以知道,如果dis[i][j]+mp[i][k]+mp[k][j] != inf(mp[i][j]为没有跟新得边值) 时就存在一条经过ijk的最小环,所以我们要求的是所有环当
中最小的哪一个!

所以有了以下AC代码

#include<bits/stdc++.h>
using namespace std;
const int N=110;
const int inf=1e8;//这里真的超级坑,不能像以前写成0x3f3f3f3f,因为会爆int
int n,m,mp[N][N],g[N][N],res=inf;
void floyd()
{
	res=inf;
	for(int k=1;k<=n;k++)
	{
		for(int i=1;i<k;i++)
			for(int j=i+1;j<k;j++)
				res=min(res,g[i][j]+mp[i][k]+mp[k][j]);
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				g[i][j]=g[j][i]=min(g[i][j],g[i][k]+g[k][j]);
	}
}
int main()
{
	while(cin>>n>>m)
	{
		for(int i=1;i<=n;i++)	for(int j=1;j<=n;j++)	if(i!=j)	mp[i][j]=g[i][j]=inf;
		while(m--)
		{
			int u,v,w;
			cin>>u>>v>>w;
			mp[u][v]=mp[v][u]=g[u][v]=g[v][u]=min(w,mp[u][v]);
		}
		floyd();
		if(res==inf)	cout<<"It's impossible."<<endl;
		else	cout<<res<<endl;
	}
	return 0;
}