您的位置:首页 > 其它

zoj 1789

2011-08-19 17:10 225 查看
 第一次写的代码超时了……这是错误代码
#include<stdio.h>
struct student        //用数组更方便一点儿
{
int t;
int father;
}student[30000];
int find(int x)
{
if(student[x].father==x)
return x;
else
return find(student[x].father);
//返回树根所代表的学生编号
}
void merge(int x,int y)
{
student[x].father=y;
}
int main()
{
int n,m,k,i,x,y,count;
for(i=0;i<30000;i++)
{
student[i].father=i;
student[i].t=0;
}
while(scanf("%d%d",&n,&m),!(n==0&&m==0))
{
while(m--)  //建立组员间的关系,即集合
{
scanf("%d",&k);
if(k!=1)
{
scanf("%d",&x);
for(i=1;i<k;i++)
{
scanf("%d",&y);
if(student[y].t==0)
{
student[y].father=x;
student[y].t=1;
}
else
{
if(x!=find(y))
merge(x,find(y));  //合并集合
}
}
}
}
//查并集
k=find(0);
for(i=1,count=1;i<n;i++)
{
if(k==find(i))   //找到属于同一个子树的元素,count++
count++;
}
printf("%d\n",count);
for(i=0;i<n;i++)
{
student[i].t=0;
student[i].father=i;
}
}
return 0;
}
/*TLE*/

 

 

改进后的代码

#include<stdio.h>
int find(int *father,int i)
{
if(father[i]==i)
return i;
else
return find(father,father[i]);
}
int main()
{
int father[30000],i,k,n,m,x,y,count;
for(i=0;i<30000;i++)
father[i]=i;
while(scanf("%d%d",&n,&m),!(m==0&&n==0))
{
while(m--)
{
scanf("%d",&k);
if(k!=0)
{
scanf("%d",&x);
for(i=1;i<k;i++)
{
scanf("%d",&y);
if(father[y]==y)
father[y]=x;                       //将 y 的根和 x 连起来
else
{
if(find(father,x)!=find(father,y))
father[find(father,y)]=x;    //由于这个merge比较简单,直接写出来也很方便
}
}
}
}
k=find(father,0);
for(i=1,count=1;i<n;i++)
{
if(find(father,i)==k)
count++;
}
printf("%d\n",count);
for(i=0;i<n;i++)
father[i]=i;
}
return 0;
}


总结,查并集主要就两个步骤:

建立集合元素间的关系,即合并为一个集合(将根部相连);

void merge(int x,int y)
{
father[find(father,y)]=y;
}

对每个元素而言查找所属集合。

int find(int *father,int i)
{
if(father[i]==i)
return i;
else
return find(father,father[i]);
}


 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  merge ini