poj1258_kruskal

<pre name="code" class="cpp">/*
题意:给你一个n*n的连通图,求将他全部连起来的最小花费,即求其最小生成树
这里我们用到  Kruskal算法 和并查集算法

Kruskal算法简述
假设 WN=(V,{E}) 是一个含有 n 个顶点的连通网,则按照克鲁斯卡尔算法构造最小生成树的过程为:先构造一个只含 n 个顶点,而边集为空的子图,若将该子图中各个顶点看成是各棵树上的根结点,则它是一个含有 n 棵树的一个森林。之后,从网的边集 E 中选取一条权值最小的边,若该条边的两个顶点分属不同的树,则将其加入子图,也就是说,将这两个顶点分别所在的两棵树合成一棵树;反之,若该条边的两个顶点已落在同一棵树上,则不可取,而应该取下一条权值最小的边再试之。依次类推,直至森林中只有一棵树,也即子图中含有 n-1条边为止。
并查集算法简述
并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示。
集就是让每个元素构成一个单元素的集合,也就是按一定顺序将属于同一组的元素所在的集合合并。
对于解题方法,代码中写得很详细。
*/
#include<stdio.h>
#include<algorithm>
using namespace std; 
struct edge{
	int s,e,v;
}e[5003];//保存所有的边,s起点,e终点,v花费 
bool cmp(edge x,edge y)//按边长从小到大排序 
{
	return x.v<y.v;
}
struct tree{
	int p;//parent
	int s;//sum
}t[102];//并查集和,最终必有n个元素,p父亲节点,s个数 
int n,val,num,ans;
void init()//初始化并查集和,令根为本身,集合个数为1 
{
   for(int i=0;i<n;i++)
   {
   	  t[i].p=i;
   	  t[i].s=1;
   }
}
int find(int x)//找到x的根节点 
{
	while(x!=t[x].p)
	{
	    t[x].p=t[t[x].p].p;
		x=t[x].p;	
	}
	return x;
}
void uion(int sr,int er)//合并以sr为根的集合(a)和以er为根的集合(b)
{
	if(t[sr].s>t[er].s)//深度的优化,如果a大于b,那么将b合并到a,反之则反 
	{
		t[er].p=sr;//修改b的根 
		t[sr].s+=t[er].s;//将b的大小加到a上 
	}else{
		t[sr].p=er;
		t[er].s+=t[sr].s;
	}
}
void kruskal()
{
	init();
	for(int i=0;i<num;i++)
	{
		int sr=find(e[i].s);//起点的根 
		int er=find(e[i].e);//终点的根 
		if(sr!=er)//判断这两个点是否已经连接 
	    {
		    uion(sr,er);//合并这两个点 
		    ans+=e[i].v;//加上这两边的长度(花费),因为已经排序所以一定是最短的 
        } 
	}
}
int main()
{
	while(scanf("%d",&n)!=EOF)
	{
		num=0;
		for(int i=0;i<n;i++)
		   for(int j=0;j<n;j++)
		   {
   			   scanf("%d",&val);
		       if(i>j)//无向图取一半即可 
		       {
         	      e[num].s=i;
			      e[num].e=j;
				  e[num++].v=val;	
         	   }
		   }
	    ans=0;//初始化最小花费 
        sort(e,e+num,cmp);//按边长从小到大排序
	    kruskal();
	    printf("%d\n",ans);
	}
}


 
 
 
 

                
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值