HDU1272和HDU1325【并查集】

【HDU1272】小希的迷宫

传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1272

【分析】每组数据中输入多组两个整数代表通道连接的两个房间的编号,房间的编号至少为1。以0,0,这组数据输入结束,以-1,-1测试结束。条件:保证图是连通的,且连通分量为1( 即从一点可以到任意一点 ),不存在环(包括自环)

#include<iostream>
#include<cstdio>

using namespace std;
const int N = 100000 + 10;
int par[N];              //父节点
int vis[N];              //标记这点已经加入了最小生成树
int flag; 
int find(int x)        //查找父节点
{
	int p = x;
	while (par[p] != p)
		p = par[p];
	int i = x;
	int j;
	while (i != p)
	{
		j = par[i];
		par[i] = p;
		i = j;
	}
	return p;
}
void unionset(int x, int y)        //连接两个房间
{
	if ((x = find(x)) == (y = find(y)))   //父节点相同证明已连接,此时不需要连接
		flag = 0;
	else
		par[y] = x;               //不同的话,证明还未连接
}
void init()
{
	for (int i = 0; i<N; i++)
	{
		par[i] = i;    //父节点为自己
		vis[i] = 0;   //每个点都还未遍历
	}
}
int main()
{
	int r1, r2;
	while (scanf("%d%d", &r1, &r2) != EOF) //仅对第一对房间输入
	{
		if (r1 == 0 && r2 == 0)       //即使一开始输入00,也是对的
		{
			printf("Yes\n");
			continue;
		}
		init();
		if (r1 == -1 && r2 == -1)
			break;

		unionset(r1, r2);   //连接第一对房间号
		flag = 1;             //第一对房间被连接
		vis[r1] = 1;
		vis[r2] = 1;        //已连接做标记
		while (scanf("%d%d", &r1, &r2) && r1 && r2) //对后面的房间输入做判断
		{
			unionset(r1, r2);
			vis[r1] = 1;
			vis[r2] = 1;
		}
		if (flag == 0)           //若有成环,则输出NO
		{
			printf("No\n");
			continue;
		}
		else
		{
			int sum = 0;
			for (int i = 0; i <= N; i++)
			{
				if (vis[i] == 1 && par[i] == i)    //父节点为同一个
					sum++;
			}
			if (sum == 1)            //刚好满足条件
				printf("Yes\n");
			else                    //无环 但是不能完全连通
				printf("No\n");
		}
	}
	return 0;
}

【HDU1325】Is It A Tree?

传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1325

【分析】这两题其实很像,但是唯一的区别是,上题是无向,这题是有向的。条件:1,无环;2,除了根,所有的入度为1,根入度为0。

#include<iostream>
#include<cstdio>

using namespace std;
const int N = 100000 + 10;
int par[N];
int vis[N];
int flag;
int find(int x)
{
	if (par[x] == x)
		return x;
	else
		return find(par[x]);
}
void unionset(int x, int y)
{
	int xx = find(x);
	int yy = find(y);
	if (xx == yy)
		flag = 0;
	else
		par[y] = x;
}
void init()
{
	for (int i = 0; i<N; i++)
	{
		par[i] = i;
		vis[i] = 0;
	}
}
int main()
{
	int k = 0;
	int r1, r2;
	while (scanf("%d%d", &r1, &r2) != EOF) //仅对第一对房间输入
	{
		k++;
		flag = 1;
		if (r1<0 && r2<0)
			break;
		if (r1 == 0 && r2 == 0)       //即使一开始输入00,也是对的
		{
			printf("Case %d is a tree.\n", k);
			continue;
		}
		init();
		unionset(r1, r2);           //第一对房间
		vis[r1] = 1;
		vis[r2] = 1;
		par[r2] = r1;         //只能从r1 到 r2
		while (scanf("%d%d", &r1, &r2) && r1 && r2) //对后面的房间输入做判断
		{
			unionset(r1, r2);
			vis[r1] = 1;
			vis[r2] = 1;
		}
		if (flag == 0)   //有环
		{
			printf("Case %d is not a tree.\n", k);
			continue;
		}
		else
		{
			int sum = 0;
			for (int i = 0; i <= N; i++)
			{
				if (vis[i] == 1 && par[i] == i)   //存在这个房间并且父节点是自己
					sum++;
				if (sum>1)    //出现有不同的根节点,证明有不同的的树
					break;
			}
			if (sum>1)
				printf("Case %d is not a tree.\n", k);
			else
				printf("Case %d is a tree.\n", k);
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_40317006/article/details/81385877
今日推荐