AcWing 846. 树的重心 超详细解析

Posted 幽殇默

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AcWing 846. 树的重心 超详细解析相关的知识,希望对你有一定的参考价值。

在这里插入图片描述
https://www.acwing.com/problem/content/848/

首先要看清题目是 n个点 (n-1) 条边。

重心的定义是啥不多说,不懂的多看几次y总的视频,这不难理解。

题目给的是无向图,我们可以用有向图建两条边,来表示无向图。
题目给的点的范围是 小于1e5。

const int N=1e5+10;
const int M=N*2;
int h[N],e[M],ne[M],idx;
bool st[N];
int ans=N;

所以上面不难理解,因为是两条边故 e[ M ] , ne[ M ] ,头节点就是n个 h [ N ]

st[N]  是用来方式重复遍历的。 因为我们只需枚举每一个点一次就行了。
所以用其标记来保证每一个点只枚举一次

下面开始分析: 如何求去掉一个点后各个连通块点的个数。
在这里插入图片描述
你会发现: 取掉一个点后,此时有三个连通块(用蓝色标记)。

其实本质是两块内容

在这里插入图片描述

由上图可以看到: 本质分成了两个部分。

  • 第一部分: 以4为头节点的其每一个儿子的点的个数(我们取最大的)
  • 第二部分: 4作为一个子节点求其所对应的连通块的点数.

那么4作为子节点的点数= n(总的点数) - 4的儿子的节点数之和。

到这里我想各位应该已经懂了一大半了。
下面看代码分析:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=1e5+10;
const int M=N*2;
int n;
int h[N],e[M],ne[M],idx;
bool st[N];
int ans=N;
void add(int a,int b)//向以a头节点 加入b
{
	e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
int dfs(int u)//求以 u为头节点的子节点的点数之和
{
	st[u]=true;
	int sum=1,res=0;  //sum=1  是因为加上去掉的那个数
	for(int i=h[u];i!=-1;i=ne[i])
	{
		int j=e[i];
		if(!st[j])
		{
			int s=dfs(j);
			res=max(res,s);//  求子节点中点数最大的
			sum+=s; //求以j为头节点的子节点的点数之和
		} 
	}
	
	res=max(res,n-sum);//求头节点所在连通块  和 其子节点最大的点数 中最大的值
	ans=min(ans,res);//求我们每一种情况中,最小的值
	
	return sum;
}
int main(void)
{
	cin>>n;
	memset(h,-1,sizeof h);
	for(int i=0;i<n-1;i++)
	{
		int a,b; cin>>a>>b;
		add(a,b),add(b,a);
	} 
	dfs(4);
	cout<<ans<<endl;
	return 0;
}

首先 因为我这里举的例子是从4开始的,故写的dfs(4) 代表从 4开始枚举。
其实 dfs() 从1到n中的任何一个数枚举都是一样的,因为我们都是只枚举一遍。
不能从0开始是因为我们的节点是从1开始的。你不能枚举一个没有的点。

刚开始:
在这里插入图片描述
刚开始 4可以到的有 1 3 6
然后1 没有走过,就求去掉1后的最大点数 , 1又可以到达 2 7 以此递归。
3
6
在这里插入图片描述
我想 st[ N ] 的作用大家都知道了吧。

以上是关于AcWing 846. 树的重心 超详细解析的主要内容,如果未能解决你的问题,请参考以下文章

AcWing 846. 树的重心(DFS)

[常见做法整合]CSP-S2019 D2T3 树的重心

[数据结构] 树与二叉树的超详细解析 建议收藏 看它就够了

AcWing 252. 树 点分治

Acwing 1072. 树的最长路径

HashMap底层红黑树原理(超详细图解)+手写红黑树代码