从hdu 1233看kruskal算法和prim算法

这几天,离散数学学习了图论。自然也引起了一些我对图和树的一些有益的思考。今天,就通过一道hdu的acm题来简述最小生成树的两种基本算法---kruskal算法和prim算法。

下面是题目,在hdu的oj中编号为1233显然,这是一种求最小生成树的问题。所谓树就是由枝丫和结点而构成的数据结构。而prim和kruskal算法分别从结点和枝丫来考虑了这个问题。prim(普里姆算法)这是一种由点来构成最小生成树的算法。</p><p>首先,构建一个只有孤立点而无枝丫的空图。而后,选择一个起点a1,将其加入已知域当中,并找出距离a1最近的点标为a2,将其加入已知域当中,并更新距离已知域的距离的集合,再递归寻找距离这个已知域最近的点。循环往复,直到所有的点都被纳入已知域当中。这是第一种贪心的思路。kruskal算法这个算法就是从边来进行最小生成树生成的。设此时有n个点,首先,将路径的长短排序,选择最短的那一边,而后,选择第二条边。但此时,对这条边的端点便有了要求。由于我们要找的是最小生成树,所以每一个点只需联通1次即可,故这棵树只有n-1条边,且两两两点必然可以联通。故我们不需要联通具有同一个根的两个点(即两点是由前面的点分叉而得)。所以,我们设置了两个数组来衡量一个点的权重和母根(即下面的father和son数组),逐次递归,当生成树达到n-1条边的时候,最小生成树完成。

普里姆算法:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define infinity 0x3f3f3f3f
int road[110][110],lowcase[110];
int num;
bool map[110];
int prime()
{
	int i,j,k,temp,sum=0;
	memset(map,false,sizeof(map));
	map[1]=true;
	for(i=1;i<=num;i++)
	   lowcase[i]=road[1][i];
	for(i=1;i<=num;i++)
	{
		temp=infinity;
		for(j=1;j<=num;j++)
		{
			if(!map[j]&&temp>lowcase[j])
			{
			     temp=lowcase[j];
			     k=j;
			}
		}
		if(temp == infinity) break;
		map[k]=true;
		sum+=temp;
		for(j=1;j<=num;j++)
		{
			if(!map[j]&&lowcase[j]>road[k][j])
			       lowcase[j]=road[k][j];
		}
	}
	return sum;
}
int main()
{
	int i,a,b,c,tem,result;
	while(scanf("%d",&num)!=EOF&&num)
	{
	 	 memset(road,infinity,sizeof(road));
	    tem=(num*(num-1))/2;
	    for(i=1;i<=tem;i++)
	  {
		   scanf("%d %d %d",&a,&b,&c);
		   road[a][b]=road[b][a]=c;
	  }
	  result=prime();
	  printf("%d\n",result);
	}
	return 0;
}
kruskal算法:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
struct road
{
	int len;
	int a,b;
};
road map[5050];
int comp (road a,road b)
{
	return a.len < b.len;
}
int father[110],son[110],num,tem;
int rootsearch(int x)
{
	return x == father[x] ? x : rootsearch(father[x]);
}
int kruskal()
{
	int i,total=0,sum=0;
	int root1,root2;
	for(i=1;i<=num;i++)
	{
		son[i]=1;
		father[i]=i;
	}
	for(i=0;i<tem;i++)
	{
		root1=rootsearch(map[i].a);
		root2=rootsearch(map[i].b);
		if(root1==root2)continue;
		else if(root1>=root2)
		{
			father[root2]=root1;
			son[root1]+=son[root2];
		}
		else 
		{
			father[root1]=root2;
			son[root2]+=son[root1];
		}
		sum+=map[i].len;
		total++;
		if(total==num-1)break;
	}
	return sum;
}
int main()
{
	int result,i;
	while(scanf("%d",&num)!=EOF&&num!=0)
	{
		tem=(num*(num-1))/2;
	   for(i=0;i<tem;i++)
	       scanf("%d %d %d",&map[i].a,&map[i].b,&map[i].len);
	   sort(map,map+tem,comp);
	   result=kruskal();
	   printf("%d\n",result);
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值