树重心

一遍dfs

树的重心的性质就不用再说了,本题主要使用重心的概念进行解题即在所有节点为根的较大size(节点数)的子树当中找到节点数最小的节点。
本题最重要的是
理解如何实现一遍dfs递归找到最佳节点
算法的关键是使用递归操作所有的节点的子节点具体实现如下
使用vector<int>leaf[]来构建树存储节点及其相连的节点。
now表示当前的节点
son表示now的子节点
parent表示now的父节点
dp[]表示now节点的size
maxsontree表示now的son中size最大的节点数
minsize表示所有节点的最大子树中节点最少的size
number表示有几个答案
answer[]表示答案的集合

#include<iostream>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
#define maxn 100005
#define INF 0x3f3f3f//表示最大的数

int n,m;
vector<int>leaf[maxn];
int dp[maxn]={0};
int minsize;
int answer[10];
int number;
void dfs(int now,int parent)
{
 int i,j;
 dp[now]=1;//默认当前节点数为1,在最底层递归时有用(但实际上应该为0但是这样就不能进行累加)。
 int maxsontree=0;
 for(i=0;i<leaf[now].size();i++){
  int son=leaf[now][i];
  if(son!=parent){//当son不是now的父节点时继续递归
   dfs(son,now);
   dp[now]+=dp[son];//now的size是所有son的size的和
   maxsontree=max(maxsontree,dp[son]);//选出now的所有son中最大的size
  }
 }
 maxsontree=max(maxsontree,n-dp[now]);//举个例子:最底层的son它最大子树的size是在父节点方向的树,但是此时dp是1(实际为0),所以用总节点数减去其dp得到的是真实节点数加1,(所有的都加1结果不受影响)。
 if(maxsontree<minsize){//一旦有更小的最大子树节点数
  number=0;//重置答案个数。
  answer[++number]=now;//存储答案
  minsize=maxsontree;
 }
 else if(maxsontree==minsize)//有相同的答案
 {
  answer[++number]=now;//让答案数加1并在下一位进行存储。
 }
}
int main()
{
 cin>>n>>m;
 int u,v,i,j;
 for(i=0;i<m;i++){
  scanf("%d %d",&u,&v);
  leaf[u].push_back(v);
  leaf[v].push_back(u);
 }
 minsize=INF;//开始假设最佳size数是极大的值。
 number=0;//初始答案数为0.
 dfs(1,0);//开始遍历
 sort(answer+1,answer+number+1);//将答案排序
 for(i=1;i<=number;i++){
  printf("%d ",answer[i]);
 }
 return 0;
}

代码在递归的哪一处不太好理解,可以自己先画一个树,从最理想的情况一直递归一条边,演算一下过程,就可以明白了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值