一、题目指路:
二、并查集基础知识:
1)Disjoint Set ,意为"不相交集合"
2)并查集用于处理一些不相交集合的合并问题
3)存储结构:静态链式结构(数组)
4)并查集类的描述:
#define Maxsize 100
int parent[Maxsize];//数组
int n;//集合元素元数
//初始化操作:
for(int i=0;i<n;i++)
parent[i]=-1; //或者:memset(parent,-1,sizeof(parent));
5)主要操作:查找算法、合并算法
//查找算法:只需要沿着节点x向上移动,直至达到parent值为-1的节点
int Find(int x)
{
while(parent[x]>=0) x=parent[x];
return x;
}
//合并算法:只有不同集合才可以合并,利用根节点的parent值以负数形式保存节点个数
bool Union(int i.int j)
{
//先找到节点i,j各自的根
int a=find(i);
int b=find(j);
int t=parent[a]+parent[b];//保存两个集合的总节点数
if(a==b) return false;//相同集合,不合并
else{
if(parent[a]<parent[b]) //因为根节点是负数,谁小说明节点多,节点多的充当新集合的根节点
{
parent[b]=a;
parent[a]=temp;
}
else{
parent[a]=b;
parent[b]=temp;
}
}
return true;
}
三、解题思路:
本题要实现“朋友的朋友是朋友”,用并查集实现集合的并。要输出某节点的朋友数,则将该节点所属的集合的根节点的parent[]值取反输出即可。
AC代码如下:考察并查集主要操作的实现
#include<bits/stdc++.h>
using namespace std;
const int MAX=1e6+10;
int N,M;
int parent[MAX];
int find(int pos)
{
while(parent[pos]>=0) pos=parent[pos];
return pos;
}
//不相交集合的并:
void Union(int i,int j)
{
if(find(i)==find(j)) return;//相同结合,不并
// i和 j的根并。
int a=find(i);
int b=find(j);
int temp=parent[a]+parent[b];
if(parent[b]<parent[a])//i节点少,j多
{
parent[a]=b;
parent[b]=temp;
}
else{
parent[b]=a;
parent[a]=temp;
}
}
void Query(int t)
{
while(parent[t]>0){
t=parent[t];
}
cout<<endl<<-1*parent[t]; //取反输出该集合所拥有的节点个数
}
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int ans=0;
int cnt=1;
while(cin>>N>>M)
{
if(cnt>1) cout<<endl<<endl;
++cnt;
memset(parent,-1,sizeof(parent));//初始化
++ans;
cout<<"Case "<<ans<<":";
while(M--)
{
char choice;
int t1,t2,t3;
cin>>choice;
switch(choice)
{
case 'M':
cin>>t1>>t2;
Union(t1,t2);
break;
case 'Q':
cin>>t3;
Query(t3);
break;
}
}
}
return 0;
}