poj1308 判断是否为树

题目:已知有m条边连接顶点,判断其是否为一棵树
思路:树的条件:
要么是空树,要么满足连通无环
1.无环(可通过并查集判断)
2.连通(不能出现森林,即所有输入的点必须只在一个集合里边)
自己wa了好几遍。
总结下来有几个原因:
1.空树特判
2.输入问题,无论是不是树,都必须输入完数据才行。
3.初始化一定要放在最前边
4.连通无环是并列关系,但是只要一个不满足,在输入完成的情况下,均可以直接输出结果,算是一点优化吧。

在网上摘别人的一些易错用例:
1: 0 0 空树是一棵树
2: 1 1 0 0 不是树 不能自己指向自己
3: 1 2 1 2 0 0 不是树....自己开始一直在这么WA  好郁闷 重复都不行呀~~5555
4: 1 2 2 3 4 5 不是树  森林不算是树(主要是注意自己)
5: 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 1  注意 一个节点在指向自己的父亲或祖先 都是错误的 即 9-->1 错
6: 1 2 2 1 0 0 也是错误的

#include <cstdio>
#include <algorithm>
#include <cstring>
#define N 105
using namespace std;

int f[N];
int sign[N];//记录出现过的顶点

void init()
{
	for (int i = 1; i <= N; i++)
		f[i] = i;
}

int find(int x)
{
	return x == f[x] ? x : f[x] = find(f[x]);
}

void merge(int x, int y)
{
	int t1 = find(x), t2 = find(y);
	if (t1 != t2)	f[t2] = t1;
}

int same(int x, int y)
{
	return find(x) == find(y);
}

int main()
{
	int x, y,cas = 0;
	while (~scanf("%d%d", &x, &y) && (x != -1 || y != -1))
	{
		if (x == 0 && y == 0)//输入点只有0,0。也就是说是空树特判
		{
			printf("Case %d is a tree.\n", ++cas);
			continue;
		}
		//初始化
		init();
		memset(sign, 0, sizeof(sign));

		int ans = 1;//假定是树	
		//标记输入顶点
		sign[x] = sign[y] = 1;
		if (x == y)//出现自环
			ans = 0;
		else//合并前两个元素
			merge(x, y);

		//先一次性输入完
		while (~scanf("%d%d", &x, &y) && (x || y))
		{
			sign[x] = sign[y] = 1;
			if (same(x, y))
				ans = 0;
			else
				merge(x, y);
		}

		if (ans == 0)//出现环
			printf("Case %d is not a tree.\n", ++cas);
		else//下边判断连通性 
		{
			int cnt = 0;
			for (int i = 1; i <= N; i++)
			{
				if (sign[i] && f[i] == i)//如果该点被标记(即出现过)并且是树根,连通分量的个数加一
					cnt++;
			}
			if (cnt > 1)//集合的连通分量大于1,即为森林
				printf("Case %d is not a tree.\n", ++cas);
			else//满足连通无环,说明是树
				printf("Case %d is a tree.\n", ++cas);
		}
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值