UVA1395-Slim Span(最小生成树Kruskal、并查集)

题目链接:点击打开链接

题意:给你一个图,求一个生成树,使其苗条度最小

苗条度:生成树的最大边减去最小边的值。


先把边的权值从大到小排序,然后,对于任意一个边值区间,都可以建立生成树,使苗条度不超过这个图的最大边减最小边。

所以说,要想找出来这个苗条度最小的生成树,就要先枚举这个区间的左端点,在此基础去枚举右端点,比如说有三个权值是3,4,5的边,首先是[3],[3,4][3,4,5]分别去建树,然后比较苗条度,取最小的,这样,所有的方案都建成之后,最小的苗条度也就出来了,当然,边要足够连接所有的点,建不了树是没有结果的,返回-1

代码及注释如下:

#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
int n,m,cnt;
int a[11000],b[11000],w[11000],p[11000],r[11000];//a,b为点的序号。w为权值,p为并查集,r是边的序号 

int cmp(const int i,const int j)
{
	return w[i]<w[j];							//间接排序 
}

int find(int x)
{
	return p[x]==x?x:p[x]=find(p[x]);			//找根函数 
}

int solve()
{
	int ans=0x3f3f3f3f,t;
	for(int i=0;i<m;i++)r[i]=i;					//边序号初始化 
	sort(r,r+m,cmp);							//将边的权值从小到大排序 
	for(int i=0;i<m;i++)
	{	
		for(int i=1;i<=n;i++)p[i]=i;				//点的序号是从1开始,且并查集是对每个序号的点初始化,所以初始化时要从1-n ! 
		cnt=n-1;									//这个cnt是用来判断是否所有的点都被合并 
		for(int j=i;j<m;j++)
		{
			int R=r[j];
			//以下三行为并查集操作 
			int x=find(a[R]);int y=find(b[R]);
			if(x!=y)
			{
				p[x]=y;
				cnt--;
			}
			//合并成树以后,才能判断是否有最小的苗条度! 所以成不了树就不能比较最小值了,因为没有苗条度 
			if(!cnt)
			{
				ans=min(ans,w[R]-w[r[i]]);
				break;
			}
		}
	}
	return ans==0x3f3f3f3f?-1:ans;
}
int main()
{
	//freopen("input.txt", "r", stdin );
 	//freopen("output.txt", "w", stdout);
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		if(n==0&&m==0)break;
		for(int i=0;i<m;i++)
		{
			scanf("%d%d%d",&a[i],&b[i],&w[i]);
		}
		printf("%d\n",solve());
	}
	return 0;
 } 


全部评论

相关推荐

不愿透露姓名的神秘牛友
11-27 10:21
点赞 评论 收藏
分享
寿命齿轮:实习就一段还拉了,项目一看就不是手搓,学历也拉了,技术栈看着倒是挺好,就是不知道面试表现能咋样。 不过现在才大三,争取搞两端大厂实习,或者一个纯个人项目+一段大厂,感觉秋招还是未来可期。
投递美团等公司10个岗位
点赞 评论 收藏
分享
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务