对于并查集: 很多次都是迷迷糊糊,尤其是对并查集的优化:
1.路径压缩 2.按秩合并
对此个人整理了一下:
对于最基本的并查集建议看看:
百度百科: http://baike.baidu.com/view/521705.htm
以例题的形式分析,并用算法描述了
博客园: 对于有点基础的可以参考下,清晰明了
http://www.cnblogs.com/cherish_yimi/archive/2009/10/11/1580839.html
对于第二个优化按秩合并的部分处理有点异议:
if(rank[x] < rank[y])
{
num[x]=y;
}
else if(rank[x]> rank[y])
{
num[y]=x;
}
else rank[y]++;
看到很多博客上都是这么写的,就连维基百科上也是这么处理的!
个人感觉这样会大大使按秩合并的优化打折,这样处理应该比上面的哪个要严谨多了
if(rank[x] <= rank[y])
{
num[x]=y;
rank[y]+=rank[x];
}
else if(rank[x]> rank[y])
{
num[y]=x;
rank[x]+=rank[y];
}
而在sdutoj 2391测试 时间只是略快
题目推荐:
poj 1611 The Suspects
http://poj.org/problem?id=1611
模版题不解释
#include<stdio.h>
#include<string.h>
#define N 30005
int num[N];int rank[N];
int match(int n)
{
if(n!=num[n])
num[n]=match(num[n]);
return num[n];
}
int main()
{
int n,m,k;
while(scanf("%d%d",&n,&m),n+m)
{
//memset(rank,1,sizeof(rank));
for(int i=0;i<=n;i++)
{
num[i]=i; rank[i]=1;
}
while(m--)
{
int a,b,x,y;
scanf("%d%d",&k,&a);
for(int i=1;i<k;i++)
{
scanf("%d",&b);
x=match(a);y=match(b);
if( x!= y )
{
if(rank[x] <= rank[y])
{
num[x]=y;
rank[y]+=rank[x];
}
else
{
num[y]=x;
rank[x]+=rank[y];
}
}
}
}
printf("%d\n",rank[match(0)]);
}
}
sdut 2391 Dark roads
http://acm.sdut.edu.cn/web/problem.php?action=showproblem&problemid=2391
#include<stdio.h>
#include<algorithm>
using namespace std;
#define N 200005
int n,m,road;
struct node
{
int s,e,cost;
}root[N];
int num[N];
int cmp(node a,node b)
{
return a.cost<b.cost;
}
int find(int x)
{
if(x!=num[x]) num[x]=find(num[x]);
return num[x];
}
void dijk()
{
for(int i=0;i<=n;i++) num[i]=i;
road=0;
for(int i=0;i<m;i++)
{
int x,y;
x=find(root[i].s);
y=find(root[i].e);
if(x!=y)
{
num[x]=y;
road+=root[i].cost;
} } }
int main()
{
while(scanf("%d%d",&n,&m),n+m)
{
int sum=0;
for(int i=0;i<m;i++)
{ int x,y,z;
scanf("%d%d%d",&x,&y,&z);
root[i].s=x;root[i].e=y;
root[i].cost=z; sum+=z;
}
sort(root,root+m,cmp);
dijk();
printf("%d\n",sum-road);
}
}
以上纯属个人见解,望大家批评指正