`
人生难得糊涂
  • 浏览: 114378 次
社区版块
存档分类
最新评论

POJ1861-Kruskal算法

 
阅读更多

之前也写过Kruskal算法,到今天才发现 原来以前的写错了。(也不能说完全错,只是效率好低)。

 

以前忽视的地方主要有两点,一是Kruskal算法,一般先对边从小到大排好序,然后从小到大区边。

这样的话,排完序以后就只要一个循环就可以走完。

二是 并查集的路径压缩,我以前对并查集合并是遍历所有的结点对两个集合合并,

而正确的做法应该是这样

int flindfather(int a)
{
if(a==father[a])
return a;
else 
return findfather(father[a]);
}

 

而其实我们还可以进行路径压缩,这才是并查集的核心所在

只要将上面的代码改写一行,就能起到很好的效果

int flindfather(int a)
{
if(a==father[a])
return a;
else 
return father[a]=findfather(father[a]);
}

 

下面是1861的代码

#include<iostream>
#include <algorithm>
using namespace std;
#define MAXSIZE 30010
#define INF 9000100
int n,m;
int father[MAXSIZE];//并查集
int head[MAXSIZE];
int next[MAXSIZE];
int e;

struct node{
	int u;
	int v;
	int w;
};
node edge[MAXSIZE];
node medge[MAXSIZE];
int num;
int ansmax,anstot;
//判断两点是否属于同一集合
int judge(int a,int b)
{
	if(father[a]==father[b])//同一集合
		return 1;
	return 0;
}
bool cmp(node &a,node &b)
{
	return a.w<b.w;
}
int findset(int a)
{
	if(a==father[a])
		return a;
	else 
		return father[a]=findset(father[a]);
}
void kruskal()
{
	sort(edge,edge+e,cmp);
	int i,j;
	num=0;
	ansmax=anstot=0;
	for(i=0;i<2*m;i++)
		father[i]=i; //初始时 每个元素属于不同的集合
	
	for(i=0;i<2*m;i++)
	{
		if(findset(edge[i].u)!=findset(edge[i].v))//如果不属于同一集合
		{
			ansmax=ansmax>edge[i].w?ansmax:edge[i].w;
			medge[num++]=edge[i];
			int tu=edge[i].u;//将所有与v一个集合的全部并入u的集合
			int tv=edge[i].v;
			father[findset(tv)]=findset(tu);
		}
		
	}

}
void addnode(int u,int v,int w)
{
	edge[e].u=u;
	edge[e].v=v;
	edge[e].w=w;
	next[e]=head[u];
	head[u]=e++;
}
int main()
{
	//freopen("in.txt","r",stdin);
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		e=0;
		int t1=m;
		while(t1--)
		{
			int a,b,c;
			scanf("%d%d%d",&a,&b,&c);
			addnode(a,b,c);
			addnode(b,a,c);
		}
		kruskal();
		printf("%d\n",ansmax);
		printf("%d\n",num);
		for(int i=0;i<num;i++)
			printf("%d %d\n",medge[i].u,medge[i].v);
	}
}

 

 

 

 

 

0
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics