并查集之起步

今晚在打比赛的时候,有一个题,如下。
Today is Ignatius' birthday. He invites a lot of friends. Now it's dinner time. Ignatius wants to know how many tables he needs at least. You have to notice that not all the friends know each other, and all the friends do not want to stay with strangers. 

One important rule for this problem is that if I tell you A knows B, and B knows C, that means A, B, C know each other, so they can stay in one table. 

For example: If I tell you A knows B, B knows C, and D knows E, so A, B, C can stay in one table, and D, E have to stay in the other one. So Ignatius needs 2 tables at least. 
InputThe input starts with an integer T(1<=T<=25) which indicate the number of test cases. Then T test cases follow. Each test case starts with two integers N and M(1<=N,M<=1000). N indicates the number of friends, the friends are marked from 1 to N. Then M lines follow. Each line consists of two integers A and B(A!=B), that means friend A and friend B know each other. There will be a blank line between two cases.
OutputFor each test case, just output how many tables Ignatius needs at least. Do NOT print any blanks. 
Sample Input
2
5 3
1 2
2 3
4 5

5 1
2 5
Sample Output
2
4

大体意思就是,

首先有n个人,然后一直有m个关系,比如说a认识b,b认识c,那么,a,b,c都相互认识,如果认识的话就坐在一张桌子上,如果不认识就另外做一张桌子,问最后一共需要几张桌子。

输入n,m。n代表有几个人,m代表有几个关系。

一开始我打算用贪心的思路,就是将第一个按照升序或者降序排序,然后再一次比较,但是这样虽然样例对了,但是提交上去是wa。然后询问了一下玉宁大佬,需要用并查集,然而之前并没有听过,于是现学了一点点。

直接从代码开始讲吧。

#include<bits/stdc++.h>
using namespace std;
int sum;
int father[1001];//父节点
int seek(int n)
{
if(n!=father[n])
           father[n]=seek(father[n]);//首先找到点,并且重新连接父节点
return father[n];
}


void peidui(int a,int b)
{
int x=seek(a);
int y=seek(b);//如果节点相同,返回。如果不相同,就需要再加一张桌子,并且重新连接节点。
if(x==y)
           return ;
sum--;
father[x]=y;
}

int main()
{
  int s,l;
  cin>>s>>l;
  for(int i=1;i<=s;i++)
           father[i]=i;
           sum=s;
  while(l--)
  {
           int k,l;
           cin>>k>>l;
           peidui(k,l);
  }
  cout<<sum<<endl;
return 0;

}

大体理解了代码之后,感觉和二叉树差不多,但是又有区别。过程和建树差不多,但是没有一开始的那个根节点,只有若干个根节点。每一个父节点对应一个关系,如果有认识的话,就将认识的那个接到当前的这个父节点上。具体解释看代码。

分割线/**************************************************************************/

可以再加上路径压缩。也就是将二叉树形式转换为从一个直接映射到该树下所有点,这里我就不打了,不算难,但是又有一个地方需要注意,在判断某两个点的根是否相同时,还是需要用到递归,不能通过直接判断两个父亲节点而给出答案,原因就是在压缩的过程中,只是压缩的当前点以下的所有的点的父节点,但是这个点往上的点的父亲节点和这个点以下的父亲节点还是不一样,所以还是需要通过递归判断。

猜你喜欢

转载自blog.csdn.net/let_life_stop/article/details/79405584