并查集总结

并查集详解:http://blog.csdn.net/dellaserss/article/details/7724401

模板:

#include <stdio.h>
#include <vector>
#include <algorithm>
using namespace std;

//并查集
struct DisjointSet {
	std::vector<int> father, rank;		//元素的父亲节点,树根元素所代表集合的rank
	//初始化
	DisjointSet(int n) : father(n), rank(n) {
		for (int i = 0; i < n; ++i)
			father[i] = i;
	}
	//查找v所在集合的代表元
	int find(int v) {
		return father[v] = father[v] == v ? v : find(father[v]);
	}
	/*非递归 
	int find(int v) {
	int p, tmp;
	p = v;
	while (v != father[v])
		v = father[v];
	while (p != v) {
		tmp = father[p];
		father[p] = v;
		p = tmp;
	}
	return v;
	}*/
	//合并x所在集合与y所在集合
	void merge(int x, int y) {
		int a = find(x), b= find(y);
		if (rank[a] < rank[b])
			father[a] = b;
		else {
			father[b] = a;
			if (rank[a] == rank[b])
				++rank[a];
		}
	}
};

例题:fjutoj2144 

很直白的并查集,维护一下num、Max、setnum即可,实测find递归形式不会爆栈

#include <stdio.h>
#include <vector>
#include <algorithm>
using namespace std;

//并查集
struct DisjointSet {
	int setnum;
	std::vector<int> father, rank, num, Max;		//元素的父亲节点,树根元素所代表集合的rank
	//初始化
	DisjointSet(int n) : father(n + 1), rank(n + 1), num(n + 1), Max(n + 1) {
		setnum = n;
		for (int i = 1; i <= n; ++i) {
			father[i] = i;
			num[i] = 1;
			Max[i] = i;
		}
	}
	//查找v所在集合的代表元
	/*
	int find(int v) {
		int p, tmp;
		p = v;
		while (v != father[v])
			v = father[v];
		while (p != v) {
			tmp = father[p];
			father[p] = v;
			p = tmp;
		}
		return v;
	}*/
	int find(int v) {
		return father[v] = father[v] == v ? v : find(father[v]);
	}
	//合并x所在集合与y所在集合
	void merge(int x, int y) {
		int a = find(x), b= find(y);
		if (a != b) {
			if (rank[a] < rank[b]) {
				father[a] = b;
				Max[b] = max(Max[a], Max[b]);
				num[b] += num[a];
			} else {
				father[b] = a;
				Max[a] = max(Max[a], Max[b]);
				num[a] += num[b];
				if (rank[a] == rank[b])
					++rank[a];
			}
			--setnum;
		}
	}
};

int main()
{
	int n, m, x, y;
	while (~scanf("%d%d", &n, &m)) {
		DisjointSet s = DisjointSet(n);
		char op[10];
		while (m--) {
			scanf("%s", op);
			if (op[0] == 'u') {
				scanf("%d%d", &x, &y);
				s.merge(s.find(x), s.find(y));
			} else if (op[0] == 's' && op[1] == 'a') {
				scanf("%d%d", &x, &y);
				if (s.find(x) == s.find(y))
					printf("1\n");
				else
					printf("0\n");
			} else if (op[0] == 'n') {
				scanf("%d", &x);
				printf("%d\n", s.num[s.find(x)]);
			} else if (op[0] == 'm') {
				scanf("%d", &x);
				printf("%d\n", s.Max[s.find(x)]);
			} else
				printf("%d\n", s.setnum);
		}
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值