并查集 POJ 2524、POJ1988、HDU1272

POJ 2524 Ubiquitous Religions

给出学生总数n,询问m对学生信仰是否一样,输入m行信仰一样的学生,输出信仰种类数量。
并查集入门(反正我就是用它入门的)

#include<iostream>
#include<cstdio>
#include<set>
#include<map>
#include<vector>
using namespace std;
struct node{
	int par;
	int rank;
}s[100000];
int cnt;
void init(int n){             //初始化
	for (int i = 1; i <= n; i++){
		s[i].par = i;
	}
}
int find(int x){				//压缩路径
	if (s[x].par == x)return x;
	else return s[x].par = find(s[x].par);
}
void unite(int x, int y){		//合并集合
	x = find(x);
	y = find(y);
	if (x == y)return;
		cnt--;                    //计算合并次数
	if (s[x].rank < s[y].rank){
		s[x].par = y;
	}
	else
	{
		s[y].par = x;
		if (s[x].rank == s[y].rank)s[x].rank++;
	}
}
int main()
{
	int n, m;
	int num = 1;
	while (~scanf("%d%d", &n, &m)){
		if (n == 0 && m == 0)break;
		init(n); 
		cnt = n;
		for (int i = 0; i < m; i++){
			int a, b;
			scanf("%d%d", &a, &b);
			unite(a, b);
		}
		printf("Case %d: %d\n", num, cnt);
		num++;
	}
}

Cube Stacking POJ - 1988

Farmer John and Betsy are playing a game with N (1 <= N <= 30,000)identical cubes labeled 1 through N. They start with N stacks, each containing a single cube. Farmer John asks Betsy to perform P (1<= P <= 100,000) operation. There are two types of operations:
moves and counts.

  • In a move operation, Farmer John asks Bessie to move the stack containing cube X on top of the stack containing cube Y.
  • In a count operation, Farmer John asks Bessie to count the number of cubes on the stack with cube X that are under the cube X and report that value.

Write a program that can verify the results of the game.
Input

  • Line 1: A single integer, P

  • Lines 2…P+1: Each of these lines describes a legal operation. Line 2 describes the first operation, etc. Each line begins with a ‘M’ for a move operation or a ‘C’ for a count operation. For move operations, the line also contains two integers: X and Y.For count operations, the line also contains a single integer: X.

Note that the value for N does not appear in the input file. No move operation will request a move a stack onto itself.
Output
Print the output from each of the count operations in the same order as the input file.
Sample Input
6
M 1 6
C 1
M 2 4
M 2 6
C 3
C 4
Sample Output
1
0
2

本文参照博客http://blog.csdn.net/ascii991/article/details/7536826所写
看了他的博客后我发现代码在oj上通过不了,做了点小小的修改,并在我理解困难的地方加了解释

fa[]父节点位置,d[x]是x距离根节点的垂直距离,s[x]是x所在树的节点数量

#include <iostream>
#include<cstdio>
using namespace std;
const int maxn = 30007;
int fa[maxn], d[maxn], s[maxn];
int p;
int find(int x)
{
	if (fa[x] == x) return x;
	int t = fa[x];
	fa[x] = find(fa[x]);
	d[x] += d[t];
     /*递归,每次对d[x]加的方向为 根->x节点。
     在这里d[x]是x到其父亲节点的距离,而非其到根节点的距离。比如,如下图。
     求d[14],find(14)的过程为:d[11]+=d[5].d[14]+=d[11].
     同时压缩路径,14直接连到5下面。*/
	return fa[x];
}

void unite(int x, int y)
{
	x = find(x);
	y = find(y);
	fa[x] = y;
	d[x] += s[y];
	s[y] += s[x];
}

int main()
{
	int i, x, y;
	char ch;
	for (i = 1; i <= maxn; i++)
	{
		s[i] = 1; d[i] = 0;fa[i] = i;
	}
	scanf("%d", &p);
	for (i = 1; i <= p; i++)
	{
		getchar();
   //这个就是防止回车作为字符被输入ch
		scanf("%c", &ch);
		if (ch=='M')
		{
			scanf("%d%d", &x, &y);
			unite(x, y);
		}
		else{			
			scanf("%d", &x);
			find(x);
    /*这里要有个find(x)在合并之后,肯能出现下面的情况,
    此时求14到跟的距离,若没有find(x),求出的是3,即14到其父亲节点的距离,
    而通过find(x),将路径压缩,
    同时从上而下将每个节点距离其父节点的距离相加,得到结果。*/
			pintf("%d\n", d[x]);

		}

	}

	return 0;

}

举例

HDU1272&POJ - 1308并查集

A tree is a well-known data structure that is either empty (null, void, nothing) or is a set of one or more nodes connected by directed edges between nodes satisfying the following properties.

There is exactly one node, called the root, to which no directed edges point.
Every node except the root has exactly one edge pointing to it.
There is a unique sequence of directed edges from the root to each node.
For example, consider the illustrations below, in which nodes are represented by circles and edges are represented by lines with arrowheads. The first two of these are trees, but the last is not.
hdu1272和poj1308的题目是一样的,不过输出结果不同。正赶上今天poj崩了,只在hdu上a了这道题。
这道题的问形成的图是不是一棵树。树的要求有:
1.入度为1(根除外),出度不限。因为我是用并查集的思想做的,所以一发现par所指的节点想要改变就说明入度大于1了。
2.没有环,不形成森林。在进行 并 的过程中,记录边数和节点数,看是否相差1.
3.一个点或者没有点也是树。(没有点也是树?orz)
——————————————
下面的代码是过hdu的,用注释的替换原来的就能a了poj的

#include<iostream>
#include<string>
#include<algorithm>
#include<stdlib.h>
#include<stdio.h>
#include<queue>
#include<vector>
using namespace std;
#define N 100000+20
#define INF 0x3f3f3f3f
#define mem(arr,a) memset(arr,a,sizeof(arr))
/*********************************/
int par[N];
int used[N];
int n, m;
int flag;
int e;
void unite(int a, int b){
	e++;
	if (par[b] == a){
		flag = 1;
		return;
	}
	par[b] = a;
}
int main(){
	int cnt = 1;
	int num = 0;
	const char*no = "No";//"is not a tree.";
	const char*yes = "Yes";// "is a tree.";
	while (cin >> n >> m){
		mem(used, 0);
		mem(par, -1);
		flag = 0;
		e = 0;
		num = 0;
		if (n == -1 && m == -1)return 0;
//		printf("Case %d ", cnt++);
		if (n == 0 && m == 0){
			cout << yes << endl;
			continue;
		}
		num = 2;
		par[n] = n;
		unite(n, m);
		while (cin >> n >> m){
			if (n == 0 && m == 0){
				if (!flag&&e == num - 1)cout << yes << endl;
				else cout << no << endl;
				break;
			}
			if (par[n] == -1){
				par[n] = n;
				num++;
			}
			if (par[m] == -1||par[m]==m){
				if (par[m]==-1)
				num++;
				unite(n, m);
			}
			else{
				flag = 1;
				continue;
			}
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值