您的位置:首页 > 其它

The Suspects(POJ - 1611)并查集

2017-08-07 19:15 489 查看
一、题目大意

有n个人和m个小组,不同小组之间的人员可以重复,人员编号从0-n-1。

现流行一种传染病,只要小组内有一个人患病,组内所有人都将被感染患病。

现在0号人员患病,求被感染患病的总人数。

二、思路分析

我一开始的思路是,给定组内成员编号,相邻的两位成员,两两合并到一个集合。

需要注意的是要路径压缩,本题数据量较大,路径压缩后复杂度将为阿克曼函数的反函数。

三、附代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<stack>
#include<queue>
#include<cstring>
#include<string>
#include<set>
#include<cmath>
#include<map>
#include<sstream>
using namespace std;
#define inf 0x3f3f3f3f
typedef long long LL;
const int maxn = 30000 + 8;

int n,m,t;
int par[maxn],po[maxn];

int Find(int a)
{
return a == par[a] ? a : par[a] = Find(par[a]);
}
void Unite(int a,int b)
{
a = Find(a);
b = Find(b);
if(a == b) return;
par[b] = a;
}
int main()
{
while(scanf("%d%d",&n,&m) == 2 && (m || n))
{
set<int> p;
memset(par, 0, sizeof par);
for (int i = 0; i < n; ++i) par[i] = i;
bool flag = false;
while(m--)
{
memset(po, 0, sizeof po);
cin >> t;
for (int i = 0; i < t; ++i) {
cin >> po[i];
p.insert(po[i]);
if(po[i] == 0) flag = true;
}
if (t >= 1) {
for(int i = 0; i < t-1; ++i){
Unite(po[i],po[i+1]);
}
/*for (int i = 1; i < t; ++i) {
Unite(po[0], po[i]);
}*/
}
}

if(!flag){
cout << 1 << endl;
continue;
}

set<int>::iterator it;
int ans = 0;
int root = Find(0);
//cout << root << endl;
/*for(it = p.begin(); it != p.end(); ++it){
cout << *it << " " << par[*it] << endl;
}*/
for(it = p.begin(); it != p.end(); ++it){
if(Find(*it) == root){
ans++;
}
}
cout << ans << endl;
}
return 0;
}
/*
10 2
5 0 1 2 3 4
4 5 3 6 7
0 0

0 5
1 0
2 0
3 5
4 0
5 5
6 5
7 5
8
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: