欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

并查集 Suspects Cube stacking

程序员文章站 2022-06-04 08:10:00
...

POJ1611 The Suspects
n个学生分属m个团体,(0 < n <= 30000 , 0
<= m <= 500) 一个学生可以属于多个团体。
一个学生疑似患病,则它所属的整个团体都
疑似患病。已知0号学生疑似患病,以及每个
团体都由哪些学生构成,求一共多少个学生
疑似患病。
解法:最基础的并查集,把所有可疑的都并一
块。
Sample Input
100 4
2 1 2
5 10 13 11 12 14
2 0 1
2 99 2
200 2
1 5
5 1 2 3 4 5
1 0
0 0
Sample Output
4
1
1

#include <iostream>
#include <cstdio>
using namespace std;
const int MAX = 30000;
int n,m,k;
int parent[MAX+10];
int total[MAX+10];
//total[GetRoot(a)]是a所在的group的人数
int GetRoot(int a)
{ //获取a的根,并把a的父节点改为根
if( parent[a]!= a)//不是根节点
parent[a] =
GetRoot(parent[a]);//a的父亲等于父亲的父亲
return parent[a];
}
void Merge(int a,int b)
{
int p1 = GetRoot(a);
int p2 = GetRoot(b);
if( p1 == p2 )
return;
total[p1] += total[p2];//总长度
parent[p2] = p1;//改变父节点
}
int main() 
{
  while(true) 
  {
scanf("%d%d",&n,&m);
if( n == 0 && m == 0)  break;
for(int i = 0;i < n; ++i) {
parent[i] = i;  total[i] = 1;
}
for(int i = 0;i < m; ++i) 
{ int h,s;
scanf("%d",&k); scanf("%d",&h);
for( int j = 1; j < k; ++j) 
 {
scanf("%d",&s);//与刚刚输入的第一个
Merge(h,s);//合并
 }
}
printf("%d\n",total[GetRoot(0)]); 
}
return 0;
}

POJ 1988 Cube stacking
有N(N<=30,000)堆方块,开始每堆都是一个
方块。方块编号1 – N. 有两种操作:
M x y : 表示把方块x所在的堆,拿起来叠放
到y所在的堆上。
C x : 问方块x下面有多少个方块。
操作最多有 P (P<=100,000)次。对每次C操
作,输出结果。
解法:
除了parent数组,还要开设
sum数组:记录每堆一共有多少方块。
若parent[a] = a, 则sum[a]表示a所在的堆的
方块数目。
under数组,under[i]表示第i个方块下面有多少
个方块。
under数组在 堆合并和 路径压缩的时候都要更
新。
并查集 Suspects Cube stacking

#include <iostream>
#include <cstdio>
using namespace std;
const int MAX = 31000;
int parent[MAX];
int sum[MAX]; // 若parent[i]=i,sum[i]表示砖块i所在堆的砖块数目
int under[MAX]; // under[i]表示砖块i下面有多少砖块
int GetRoot(int a)
{//获取a的根,并把a的父节点改为根
if( parent[a] == a)
return a;
int t = GetRoot(parent[a]);
under[a] += under[parent[a]];
parent[a] = t;
return parent[a];
}
void Merge(int a,int b)
//把b所在的堆,叠放到a所在的堆。
{  int n;
int pa = GetRoot(a);
int pb = GetRoot(b);
if( pa == pb )
return ;
parent[pb] = pa;//根为pa
under[pb] = sum[pa]; //under[pb] 赋值前一定是0,因为
//parent[pb] = pb,pb一定是原b所在堆最底下的
//under等于父节点的sum
sum[pa] += sum[pb];
}
int main()
{
int p;
for(int i = 0; i < MAX; ++ i) {//初始化
sum[i] = 1;
under[i] = 0;
parent[i] = i;
}
scanf("%d",&p);
for( int i = 0;i < p; ++ i) {
char s[20];  int a,b;
scanf("%s",s);
if( s[0] == 'M') {
scanf("%d%d",&a,&b);
Merge(b,a);
}
else {
scanf("%d",&a);
GetRoot(a);
printf("%d\n",under[a]);
}
}
return 0;
}

来自于北京大学暑期课《ACM/ICPC竞赛训练》
北京大学信息学院 郭炜老师

相关标签: poj