您的位置:首页 > 其它

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

2017-02-09 01:16 441 查看
本题可抽象为求各个连通子图的顶点数的最大值。进一步抽象为求各个集合的个数的最大值。同样采用并查集实现集合的合并。

  以下有两个版本。改进版是看完《机试指南》后启发,将统计集合元素数的操作封装进了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.
样例输入:
4
1 2
3 4
5 6
1 6
4
1 2
3 4
5 6
7 8

样例输出:
4
2


原版:

#include <iostream> 
#define MAXSIZE 10000000
using 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&&union
for (int i=0;i<n;i++){
cin>>a>>b;
a-=1;b-=1;
ufs.unionSet(a,b);
}
//count
mostSet=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 10000000
using 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&&union
for (int i=0;i<n;i++){
cin>>a>>b;
a-=1;b-=1;
ufs.unionSet(a,b);
}
//count
if(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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  并查集 连通分量