杭电1232——并差集

杭电1232——并差集

原题链接
简单的并差集模板题,大佬的并差集详解传送门
解题思路:我们可以逆向考虑,给定n个村庄,要把所有村庄都连起来,最少需要len=n-1条路。在输入的样例中,只要有两个村庄从未连接的状态变换到连接的状态,就让len减一,将所有的样例判断完之后,len就是答案。

并差集的作用:

  1. 判断两个节点是否已经相连;
  2. 将两个没有相连的节点连起来。

fin函数的作用:fin(D)返回的是A。
一个树
已过代码:

# include <iostream>
# include <algorithm>
# include <cstdio>
# include <cstdlib>
# include <string>
# include <cstring>
using namespace std;

int id[1003] = { 0 };//标记当前节点的父亲,注意id数组的初始化问题。
int ra[1003] = { 0 };//标记当前节点的度,注意ra数组的初始化问题。
int find(int x) {//返回x最上面的父亲
	return id[x] = id[x] == x ? x : find(id[x]);
	/*
	如果x的父亲是x,说明已经搜索到头了,返回id[x]就行;
	如果x的父亲不是x,就让x的父亲等于x最上面的父亲(路径压缩)
	这么做的好处就是:只要搜索过x,再次进行搜索的时候,就不用重新搜索,只需要搜一次就行
	id[x]记录的就不是x的父亲,而是x最上面的父亲。
	*/
}

void meg(int x, int y) {//将x节点和y节点连接,更新id数组
	int a = find(x), b = find(y);
	if (ra[a] < ra[b]) {//判断a,b的度,度大的作为度小的父亲
		id[a] = b;
	}
	else {
		id[b] = a;
		if (ra[a] == ra[b]) {//如果两个节点的度相等,让a当做b的父亲,a的度加一,
			ra[a]++;
		}
	}
}
bool same(int x, int y) {
	return find(x) == find(y);//找到a,b最上面的父亲,判断是否相等。
}
int main() {
	int m, n;
	while (true) {
		int x, y;
		cin >> n;
		if (n == 0)
			break;
		cin >> m;
		int len = n - 1;
		for (int i = 1; i <= n; i++) {
			id[i] = i;//刚开始的时候所有节点的父亲都是自己。
		}
		memset(ra, 0, sizeof(ra));//将ra数组清零。
		for (int i = 0; i < m; i++) {
			cin >> x >> y;
			if (same(x, y)) {//如果x,y已经相连,不做任何处理。
				continue;
			}
			else {//如果x,y没有连接,就用meg函数,把x,y连起来,让len减一。
				meg(x, y);
				len--;
			}
		}
		cout << len << endl;
	}
	return 0;
}

最后:如果有小伙伴想刷杭电并差集的,可以参考以下大佬总结的。

简单并查集
1213 How Many Tables
1232 畅通工程

简单最小生成树
1233 还是畅通工程
1863 畅通工程
1874 畅通工程再续
1875 继续畅通工程
1162 Eddy’s picture
1102 Constructing Roads
1301 Jungle Roads
(可以通过最小生成树练习并查集)

稍微有点难度并查集
1272 小希的迷宫
1325 Is It A Tree?
1856 More is better

有点难度的并查集
1116 Play on Words
1829 A Bug’s Life
1198 Farm Irrigation
3635 Dragon Balls
2473 Junk-Mail Filter
3172 Virtual Friends
3047 Zjnu Stadium
3038 How Many Answers Are Wrong
1558 Segment set
1598 find the most comfortable road
3461 Code Lock
2818 Building Block
3367 Pseudoforest
3234 Exclusive-OR

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值