【图论】Floyd找无向图最小环 poj 1734

Floyd求无向图最小环#

算法思想##

如果若干个点形成一个环,则该环对应的有限点集V一定含有最大编号的点Kmax,按编号小到大枚举这个最大点k。

枚举时,以k为外层循环,每层循环考虑:

只经过前k-1个点的i,j间最短路径d[i][j],连接i,k的边g[i][k],连接k,j的边g[k][j],若d[i][j]+g[i][k]+g[k][j]<mn,则更新最小环的长度,同时记录路径,该环路径包含了曾经的k-1个点中的最短路上的点,也包括i,j,k三点,放入答案数组中即可。

若要统计最小环的个数,则可以在mn==d[i][j]+g[i][k]+g[k][j]时计数,要注意,如果mn在后续被更新,该计数个数要重置。

变量定义##

d[i][j]:从i到j的最短路径长

g[i][j]:连接i和j的最小边长(直接相连)

pos[i][j]:在Floyd中更新了i,j间最短路径的点

mn: 最小环的长度

代码 POJ 1734(模板题)##

#include<cstdio>
#include<iostream>
#include<vector>
using namespace std;

const int maxn=101;
const int _INF=0x7fffffff;
const int INF=_INF/3;
int n,m;
int d[maxn][maxn],g[maxn][maxn],pos[maxn][maxn];
int id,mn;
int path[maxn],cnt;

void floyd()
{
	mn=INF;
	for(int k=1;k<=n;k++)
	{
		for(int i=1;i<k;i++)
			for(int j=i+1;j<k;j++)
			{
				if(mn>d[i][j]+g[i][k]+g[k][j])
				{
					mn=d[i][j]+g[i][k]+g[k][j];
					cnt=0;
					int t=i;
					while(t!=j)
					{
						path[++cnt]=t;
						t=pos[j][t];
					}
					path[++cnt]=j;
					path[++cnt]=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])
				{
					pos[i][j]=pos[k][j];//无向图,每次更新pos[i][j]即可(当循环至j=i,i=j时,pos[j][i]=pos[k][i] ) 
					d[i][j]=d[i][k]+d[k][j];
				}
			}
	}
}

void init()
{
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			{
				pos[i][j]=i;
				if(i!=j)	g[i][j]=d[i][j]=INF;
				else	g[i][j]=d[i][j]=0;
			}
}

int main()
{
	scanf("%d%d",&n,&m);
	init();
	for(int i=1;i<=m;i++)
	{
		int x,y,c;
		scanf("%d%d%d",&x,&y,&c);
		if(c<g[x][y]) d[x][y]=d[y][x]=g[x][y]=g[y][x]=c;
	}
	floyd();
	if(mn==INF) printf("No solution.\n");
	else
	{
		for(int i=1;i<=cnt;i++) printf("%d ",path[i]);
	}
	
	return 0;
}
posted @ 2019-10-28 17:39  JWizard  阅读(265)  评论(0)    收藏  举报