1.问题引出
假设有10个强盗,请问他们一共几伙人?
已知:
1号强盗与2号强盗是一伙,
3号强盗与4号强盗是一伙,
5号2号一伙,
4号6号一伙
2号6号一伙,
8号7号一伙,
9号7号一伙,
1号6号一伙,
2号4号一伙,
请问10个强盗一共是几伙人?
2.方法思路
1.首先我们先设立一个数组f[11] , 并对其初始化 , 从1号元素到10号元素,分别赋值1,2,3……10。
int f[11];
for(int i=1;i<=10;i++)
{
f[i] = i;
}
这段代码表示给每个强盗进行编号,1号强盗编码为1,2号强盗编码为2,……。
2.其次,对强盗进行合并。我们这里写一个merge()函数,将两个强盗合并为一伙。
void merge(int v,int u)
{
int t1,t2; //假设t1是v的首领,t2是u的首领,
t1 = getf(v); //我们用一个函数getf()来寻找其v的首领t1,u的首领t2,
t2 = getf(u);
if(t1 != t2)
//如果他们两个人的首领相同,他们自然是一伙人。如果不相同就要合并为一伙。
{
f[t2] = t1; //这里我们规定左为大,即把右边一伙的首领当做左边一伙的小弟,合并为一伙。
}
上面是不是有点迷糊?对getf()不清楚到底是干什么用的。下面就来详细介绍一下:
首先,我们认为10个强盗每个人各自为1伙,一共10伙人,各自为政,所以f[i] = i;他们每个人的领导都是自己。
接下来,假如有人告知1号和2号为1伙,那么这伙人就要有个领导,本例中我们普遍认为号码小的更厉害,让其当做领导。即1号和2号领导都为1。同理3号和4号为1伙,则3号,4号领导都为3,全局变量数组f中的值即为他们的领导值,随着已知信息的不断变化(即告诉你谁谁是一伙),f中的值也不断变化(每个人的领导动态发生变化)。
如果他们的领导相同,那他们自然是一伙人,不用改变,否则就要合并这伙人,把号码小的人当做这伙人的领导。
自然,这里就要自己定义一个函数getf()来寻找每个人的领导。
int getf(int m)
{
if(f[m]==m)
return m; //如果他的领导是自己,自然得到。
else
{
f[m] = getf(f[m]);
return f[m]; //否则递归寻找自己的领导。
}
}
3.输入条件,由题目得:1和2是一伙,3和4是一伙,……,我们建一个循环输入语句,输入条件,并对其进行合并。
int n,m;
for(int y=0;y<9;y++)
{
cin>>n>>m;
merge(n,m);
}
4.显然,经过多次处理后,f数组已经分组完成,有几伙强盗,即有几个f[i] 与 i 值相同的个数,即他们最大的领导的个数,设立一个计数变量count,如果f[i]与i相同则count++。
int count = 0;
/*
……//相关代码
*/
for(int z = 1;z<=10;z++)
{
if(f[z] == z)
count++;
}
cout<<count<<endl; //输出共有几伙人
5.得出答案。
3.完整代码:(c++)
#include <iostream>
using namespace std;
int f[11];
int getf(int m)
{
if(f[m]==m)
return m;
else
{
//f[m] = getf(f[m]);
return getf(f[m]);
}
}
void merge(int v,int u)
{
int t1,t2;
t1 = getf(v);
t2 = getf(u);
if(t1 != t2)
{
f[t2] = t1;
}
}
int main()
{
int result = 0; //为了区分,这里用result代替count。
for(int i=1; i<=10; i++)
{
f[i] = i;
}
int n,m;
for(int j=0; j<9; j++) //题目告诉9条信息
{
cin>>n>>m;
merge(n,m);
}
for(int z=1;z<=10;z++)
{
if(f[z]==z)
result++;
}
cout<<result<<endl;
return 0;
}
4.运行结果
Input
1 2
3 4
5 2
4 6
2 6
8 7
9 7
1 6
2 4
Output
3
Tips
数组 f= { 5 1 5 3 5 3 8 9 9 10 }
分别对应 i= { 1 2 3 4 5 6 7 8 9 10 }
5.其他例题:
HDOJ:畅通工程(经典)1232、1558、1811、1829、1198。UESTC:203、1070。
hdu1232:
#include <iostream>
#include <cstring>
using namespace std;
int f[1005];
int getf(int m)
{
if(f[m] == m) return m;
else{
f[m] = getf(f[m]);
return f[m];
}
}
void merge(int v, int u){
int t1, t2;
t1 = getf(v);
t2 = getf(u);
if(t1 != t2){
f[t2] = t1;
}
}
int main(){
int n, m; //n: number of Cities , m: roads between these cities
int r1, r2; // 2 point of One road.
while(cin >> n >> m,n){
int cnt = 0;
for(int i = 1; i <= n; i++)
f[i] = i;
for(int j = 1; j <= m; j++)
{
cin >> r1 >> r2;
merge(r1, r2);
}
//count the joint city number.
for(int k = 1; k <= n; k++)
{
if(f[k] == k) cnt++;
}
cout << cnt - 1 << endl;
}
return 0;
}
6.致谢
《啊哈算法》这本书详细的介绍了并查集的具体问题并提供实例,借鉴良多。特别感谢!