深搜实现基于多叉树的操作(洛谷P6591)

这篇博客介绍了无向无环连通图的子树遍历问题,提供了两种解决方案:暴力方法和深度优先搜索(DFS)。在DFS中,通过孩子链表存储法构建图,并通过递归实现子树大小的计算。关键在于判断所有子节点的子树大小是否一致,以确定能否作为根节点。代码示例详细解释了DFS的实现过程。
摘要由CSDN通过智能技术生成

今天做了个题
https://www.luogu.com.cn/problem/solution/P6591

无向无环连通图的子树遍历操作

首先这个题分两种办法
1.暴力平方复杂度级别
这个具体代码就不展示了

就是一一枚举每个节点作为father节点时的直连子节点的子节点数量,如果都相同那么就算上这个father

2.深搜

首先是存储
老生长谈罢了,利用vector来存储,原理是孩子链表存储法

for(int i=1;i<=n-1;i++)
	{
		cin>>a>>b;
		es[a].push_back(b);
		es[b].push_back(a);
	}

接下来是深搜
我们利用注释来对深搜进行分析
先看纯纯的深搜

int dfs(int x,int father) x:根节点 ;father:x的根节点 意义为搜索以x为根节点的子节点数
{
	int size1 = es[x].size();
	for(int i=0;i<=size1-1;i++)
		if(es[x][i] != father)
		{
			d[x] += dfs(es[x][i],x);d[x]代表x的子树大小 注意!是子树大小不是子节点数!
		}
	++d[x];为了避免重复搜索,虽然父节点在dfs的时候没算上,但父节点也是所谓子节点的一个,所以也要算上。
	return d[x];递归返回
}

再来看加上了判断的深搜

int dfs(int x,int father)
{
	int size1 = es[x].size(),num = 0;num用来暂存子树大小,嗯对,或许写成temp更好理解,或者temp_num
	root[x] = 1;在一开始我们判定每个节点都可以成为根 毕竟一开始你还没加子树,子树为0成为根也说得过去
	for(int i=0;i<=size1-1;i++) 搞他所有子节点得到子树大小
		if(es[x][i] != father) 防止形成闭环
		{
			d[x] += dfs(es[x][i],x);
			if(!num) 此时num为0代表还没有存到子树的大小,那么就让我们给他第一个值,也可以说是基准值
				num = d[es[x][i]]; //d[x]是x子树的大小,d[es[x][i]] 就是x的一个子节点的子树的大小
			if(num != d[es[x][i]])如果后来的值和基准值不相等就可以寄了
                root[x] = 0; 寄了
		}
	++d[x];
	if(x != 1 && num && num != n - d[x])  根节点和叶子节点跳过
        root[x] = 0;
	return d[x];
}

至于这个
num != n - d[x]
额,x的一个子节点的子树的大小!=总节点数-x子树的大小,,啊这,自己琢磨琢磨

完整代

#include <bits/stdc++.h>
using namespace std;
vector <int> es[1000000+100];
bool root[1000000+100];
int d[1000000+100],n;
int dfs(int x,int father)
{
	int size1 = es[x].size(),num = 0;
	root[x] = 1;
	for(int i=0;i<=size1-1;i++)
		if(es[x][i] != father)
		{
			d[x] += dfs(es[x][i],x);
			if(!num)
				num = d[es[x][i]];
			if(num != d[es[x][i]])
                root[x] = 0;
		}
	++d[x];//为了避免重复搜索,虽然父节点在dfs的时候没算上,但父节点也是子节点的一个,所以也要算上。
	if(x != 1 && num && num != n - d[x])
        root[x] = 0;
	return d[x];
}
int main()
{
	cin>>n;
	int a,b;
	for(int i=1;i<=n-1;i++)
	{
		cin>>a>>b;
		es[a].push_back(b);
		es[b].push_back(a);
	}
	dfs(1,0);
	for(int i=1;i<=n;i++)
		if(root[i])
           cout<<i<<" ";
           cout<<endl;
	return 0;
}

参考:https://www.luogu.com.cn/problem/solution/P6591
题解第二篇

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值