pku 3522 Slim Span

题意很简单,就是找出一棵最大边值与最小边值差值最小的生成树,首先,从i=0开始枚举以当前边为最小用kruskal 算法求最小生成树,找出最小的差值

本来是1A的,不过那个时间500+ms 实在太难接受了,所以一直在剪枝,中间WA了几次,最后,嘻嘻,如愿以偿了,47ms,主要是减少不必要的循环

排完序之后,自然是开始枚举生成树的起始边

1)若以当前的起始边e[i]用kruskal算法求出的生成树是非联通的,则不用枚举了,因为之后也没法形成联通的生成树了

2)在kruskal算法过程中,若出现边值与起始边值的差值大于已求得的最小差值ans,则也可以退出循环了,但还是要继续枚举起始边,退出的是kruskal算法,因为之后还是有可能出现更小的差值的

ps:就是在这里多WA了几次

#include<iostream>
#include<string>
#include<algorithm>
#define MAXN 1001*500
using namespace std;
int f[101],n,m,ans;
struct edge
{
	int u,v,w;
}e[MAXN];
inline void init()
{
	for(int i=0;i<=n;i++)
		f[i]=i;
}
inline int find(int x)
{
	while(x!=f[x])
	{
		f[x]=f[f[x]];
		x=f[x];
	}
	return f[x];
}
inline int Union (int i)
{
	int a=find(e[i].u);
	int b=find(e[i].v);
	if(a==b) return 0;
	f[b]=a;
	return e[i].w;
}
bool cmp(edge a,edge b){
	return a.w<b.w;
}
inline int kruskal(int s)
{
	int p,max1=0;
	init();
	int num=0;
	for(int i=s;i<m;i++)
	{
		p=Union(i);
		if(p)
		{
		  max1=p;
		  num++;
		if(num>=n-1) break;
		}
		if(e[i].w-e[s].w>ans&&ans!=-1) return 0;	
	}
	for(int i=2;i<=n;i++)
		if(find(i)!=find(i-1))
			return -1;
	return max1;
}
int main()
{
	while(scanf("%d %d",&n,&m)==2&&(n||m))
	{
		for(int i=0;i<m;i++)
			scanf("%d %d %d",&e[i].u,&e[i].v,&e[i].w);
		sort(e,e+m,cmp);
		ans=-1;
		for(int i=0;i<=m-n+1;i++)
		{
			int tmp=kruskal(i);
			if(tmp>0)
			{
				tmp=tmp-e[i].w;
				if(ans>tmp||ans==-1)
					ans=tmp;
			}
			if(tmp==-1) break;//当前以i条边形成的 树不连通
		}
		printf("%d\n",ans);
	}
	return 0;
}
posted @ 2011-08-20 14:17  枕边梦  阅读(220)  评论(0编辑  收藏  举报