hdu1272

hdu1272

小希的迷宫

0x00 Tags

并查集

0x01 题目简介

  1. 并查集产生的每一个集合都是一棵树
  2. 流程:初始化;查找–判断两个元素是否在一个集合;合并
  3. 查找过程递归可能会爆栈,采用递归方式进行路径压缩
  4. 用并查集判断是否有环;对同一个集合来说只存在一个根节点
  5. 合并的过程是一个建树的过程,当合并失效时,说明两个节点在同一个集合中,这两点连的边成环
  6. 使用isroot数组记录有几个根节点–有几个不同的集合

判断是否连通:顶点数==边数+1

0x02 代码

代码—与上面思想相同

#include<bits/stdc++.h>

using namespace std;


const int maxn = 100010;

int root[maxn];

// 成环标志
bool circle;

void Init()
{
	for (int i = 1; i < maxn; i++)
	{
		root[i] = i;
	}
}

int Find(int x)
{
	//return x == root[x] ? x : Find(root[x]);

	while (x != root[x])
	{
		x = root[x];
	}

	return x;
}


void Union(int x, int y)
{
	x = Find(x);
	y = Find(y);

	if (x != y) root[x] = y;
	else circle = 0;  // 成环
}



int main()
{
	set<int> v;  // 记录顶点

	int a, b, sum;  // sum记录边数

	while (scanf("%d%d",&a,&b) != EOF)
	{
		if (a == -1 && b == -1) break;

		if (a == 0 && b == 0)
		{
			printf("Yes
");
			continue;
		}

		Init();

		sum = 1;
		circle = false;
		v.insert(a);
		v.insert(b);

		if (!circle)
			Union(a, b);

		while (1)
		{
			scanf("%d%d", &a, &b);

			if (a == 0 && b == 0) break;

			v.insert(a);
			v.insert(b);

			if (!circle) Union(a, b);

			sum++;
		}

		/*
		while (scanf("%d%d", &a, &b) != EOF)
		{
			if (a == 0 && b == 0) break;
			v.insert(a);
			v.insert(b);
			
			if (!circle) Union(a, b);
			sum++;
		}

		*/

		if (!circle && v.size() == sum + 1)
			printf("Yes
");
		else
			printf("No
");

		v.clear();
	}

	return 0;
}

代码二

#include<bits/stdc++.h>

using namespace std;


const int maxn = 100010;

int root[maxn], sign[maxn];

// 成环标志
int flag;

void Init()
{
	for (int i = 1; i < maxn; i++)
	{
		root[i] = i;
		sign[i] = 0;
	}
}

int Find(int x)
{
	//return x == root[x] ? x : Find(root[x]);

	while (x != root[x])
	{
		x = root[x];
	}

	return x;
}


void Union(int x, int y)
{
	x = Find(x);
	y = Find(y);

	if (x != y) root[x] = y;
	else flag = 0;
}



int main()
{

	int a, b;

	while (scanf("%d%d",&a,&b) != EOF)
	{
		if (a == -1 && b == -1) break;

		if (a == 0 && b == 0)
		{
			printf("Yes
");
			continue;
		}

		Init();

		sign[a] = sign[b] = 1;

		flag = 1;

		Union(a, b);

		while (scanf("%d%d", &a, &b) != EOF)
		{
			if (a == 0 && b == 0) break;
			Union(a, b);
			sign[a] = sign[b] = 1;
		}

		int k = 0;
		for (int i = 1; i < maxn; i++)
		{
			if (sign[i] && root[i] == i) // 判断根节点数目
				k++;

			if (k > 1) flag = 0;
		}

		if (flag) printf("Yes
");
		else printf("No
");
	}

	return 0;
}
原文地址:https://www.cnblogs.com/LQ6H/p/12940539.html