HDU - 1213有意思的并查集/"掌门"

深夜未耕

【一个典型的并查集】

参考网址:http://blog.csdn.net/u013546077/article/details/64509038

借用了里面的掌门学说注释这道题

#include <iostream>  
using namespace std;

int pre[1010];
//你不知道吧  我一个人在寝室 放着杨千嬅的小星星 对面你发来一句话  我对着屏幕空空地说
//"我喜欢你!"
//"我喜欢你你听到了吗  听不到也没关系 我在慢慢像你靠近"
int find(int x)
{(讲成爸爸似乎不太好理解,按括号里的掌门理解)
	int r = x;//对r说,你快去找爸爸(找我们掌门)
	while (pre[r] != r)//pre里面存的是谁是谁的爸爸,如果他爸爸不是自己的话(不是祖先(pre里面存的是谁是谁的掌门)
		r = pre[r];
	//那r变成r的爸爸,r的爸爸再去找他的爸爸
//(不不不,r再去找r上面那一层,直到最后找到的就是自己是掌门为止--终极掌门哈哈哈)
	int i = x, j;
	//路径压缩...  (就这么简单吗?? 并查集)

	//这个记录一下啊,查询路径里面,问了这么多人,这么多人
	//x先赋值给i: 从x以及更多的x(下面表现为不断更替的r)都想知道
	while (i != r)//当i还没变成最终掌门的时候,就继续往下循环ing
	{
		j = pre[i];//
		pre[i] = r;
		i = j;
	}
//i=x;i的直属掌门是pre[i],也正好是路径压缩里面下一个需要重新皈依门派的人;r赋值给pre[i],就是让i明白终极掌门是r,在pre[]这个记录掌门是谁的数组里面存一下;最后j的值(pre[i]的值)给i,也就是路径压缩里面下一个需要重新皈依门派的人,继续这个循环,一路上问过的人他们的终极掌门都是r,最后返回r


	return r;//最后返回的是他们最终的掌门.jpg
}

int main()
{
	int n, m;
	int t;
	cin >> t;
	while (t--)//最开始的t仅仅代表输入   -- 输入了多少个而已
	{
		int total;
		cin >> n;
		for (int i = 1; i <= n; i++)
			pre[i] = i;//并查集的初始化:最开始他们都是自成一家的,自己是自己的掌门
		total = n;
		cin >> m;
		int p1, p2, f1, f2;
		while (m--)
		{
			cin >> p1 >> p2;
			f1 = find(p1);
			f2 = find(p2);
//从一开始,他们都自己是自己的掌门,当发现他们不是一家子的时候,这两人要结拜兄弟
//并且,不是这样的话,f1和f2都是(各自门派里)的终极掌门
//这样继续向下,让f2的掌门认成f1,下面的也都连接了起来
//也就是pre[f2] = f1;
			if (f1 != f2)
			{
				pre[f2] = f1;
				total--;
			}
		}
		cout << total << endl;
//因为有重复 的呀,如果重复total就不会减了,知道本来最开始 有多少人很重要。
	}
	return 0;
}

【另外】自己上手打了一遍,还有两个要注意:

数组稍微开大一点

for (int i = 1; i <= n; i++)
			pre[i] = i;
这里是从1开始的(好习惯?emmm)

因为编号这种东西并不会智能到从0开始  注意一下


//吐槽.....这个题怎么这么干的并查集,还是只有25A= =
// 从寒假开始第一场*64的人到现在只有 *32..还是要善始善终呀


//你看..我只要有环境,简直是无所不能啊!
// 在寝室里一个晚上都没搞好的东西....来到机房锁手机十分钟写完了  还是需要个人监督我0 0今天是和她约了早起 

//加油啦!



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值