九度OJ-1444:More is better(用并查集求集合大小)

来源:互联网 发布:淘宝卖家怎么注册帐号 编辑:程序博客网 时间:2024/06/16 03:19

本题可抽象为求各个连通子图的顶点数的最大值。进一步抽象为求各个集合的个数的最大值。同样采用并查集实现集合的合并。

  以下有两个版本。改进版是看完《机试指南》后启发,将统计集合元素数的操作封装进了unionSet函数中。将vexNum数组作为UFS的数据成员,用以记录以此下标为根的 集合的元素数,在unionSet并集时将两个集合的元素数归加和。通过这种算法使得不必写一个像原版那样的for循环,在并集结束后将所有顶点遍历找出最大值(由于这个for循环中遍历时对每个顶点都调用了findRoot函数去求根,会增加很多开销,这也是为什么改写了之后时间开销一下子节省了1/4的缘故)。


题目描述:

Mr Wang wants some boys to help him with a project. Because the project is rather complex, the more boys come, the better it will be. Of course there are certain requirements.Mr Wang selected a room big enough to hold the boys. The boy who are not been chosen has to leave the room immediately. There are 10000000 boys in the room numbered from 1 to 10000000 at the very beginning. After Mr Wang's selection any two of them who are still in this room should be friends (direct or indirect), or there is only one boy left. Given all the direct friend-pairs, you should decide the best way.

输入:

The first line of the input contains an integer n (0 ≤ n ≤ 100 000) - the number of direct friend-pairs. The following n lines each contains a pair of numbers A and B separated by a single space that suggests A and B are direct friends. (A ≠ B, 1 ≤ A, B ≤ 10000000)

输出:

The output in one line contains exactly one integer equals to the maximum number of boys Mr Wang may keep.

样例输入:
41 23 45 61 641 23 45 67 8
样例输出:
42


原版:

#include <iostream> #define MAXSIZE 10000000using namespace std;struct UFS{//UnionFindSet 从0开始 int elem[MAXSIZE];int size;void initiate(int size){this->size=size;for (int i=0;i<size;i++)elem[i]=-1;}int findRoot(int x){if (elem[x]==-1) return x;else return elem[x]=findRoot(elem[x]);}void unionSet(int x,int y){int xroot=findRoot(x),yroot=findRoot(y);if (xroot!=yroot)//if x and y are from different set elem[xroot]=yroot; //merge xset into yset }};UFS ufs;int vexNum[10000000];int main(){int n;int a,b;int root;int mostSet,mostNum;// mostSet是目前最多顶点的集合的根的下标 mostNum是目前最多顶点集合的顶点数 while (cin>>n){//n vexes,m edges//initiate ufs.initiate(10000000);for (int i=0;i<ufs.size;i++){vexNum[i]=0;}//input&&unionfor (int i=0;i<n;i++){cin>>a>>b;a-=1;b-=1;ufs.unionSet(a,b);}//countmostSet=0;mostNum=vexNum[0];for (int i=0;i<ufs.size;i++){root=ufs.findRoot(i);//得到此顶点所在集合的根 vexNum[root]++;if (vexNum[root]>mostNum){mostNum=vexNum[root];mostSet=root;}}//output cout<<mostNum<<endl;}return true;}


改进版:

#include <iostream> #define MAXSIZE 10000000using namespace std;struct UFS{//UnionFindSet 从0开始 int elem[MAXSIZE];int vexNum[10000000];int size;void initiate(int size){this->size=size;for (int i=0;i<size;i++)elem[i]=-1;for (int i=0;i<size;i++)vexNum[i]=1;}int findRoot(int x){if (elem[x]==-1) return x;else return elem[x]=findRoot(elem[x]);}void unionSet(int x,int y){int xroot=findRoot(x),yroot=findRoot(y);if (xroot!=yroot){//if x and y are from different set elem[xroot]=yroot; //merge xset into yset vexNum[yroot]+=vexNum[xroot];vexNum[xroot]=0;}}};UFS ufs;int main(){int n;int a,b;int root;int mostSet,mostNum;// mostSet是目前最多顶点的集合的根的下标 mostNum是目前最多顶点集合的顶点数 while (cin>>n){//n vexes,m edges//initiate ufs.initiate(10000000);//input&&unionfor (int i=0;i<n;i++){cin>>a>>b;a-=1;b-=1;ufs.unionSet(a,b);}//countif(n==0)mostNum=1;else{//union完毕,此时并查集已定型 mostNum=ufs.vexNum[0];for (int i=0;i<ufs.size;i++){if (ufs.vexNum[i]>mostNum)mostNum=ufs.vexNum[i];}//output cout<<mostNum<<endl;}return true;}



0 0