求树的重心(链式前向星,vector存边)

树的重心:找到一个点,其所有的子树中最大的子树节点数最少.

给出节点为n的树

下面n-1行为点连接关系

如:

4

1 3

1 2

2 4

一,链式前向星:

#include <iostream>
const int N=2e5+5;
using namespace std;
int head[N],son[N],dp[N],n,k=0,mins=1e9;
//son:某节点的子树节点数
//dp:某节点的最大子节点数
//mins:最小的最大子节点数
bool fa[N];
struct edge
{
	int u,v,nxt;
}e[N];

void  add(int u,int v)
{
	k++;
	e[k].v=v;
	e[k].nxt=head[u];
	head[u]=k;
}

void dfs(int u,int f)

{
	son[u]=1;//叶子节点初始为1
	for(int i=head[u];i;i=e[i].nxt)//i=e[i].nxt取得前向
	{
		int v=e[i].v;
		if(v!=f)//取得节点不是父节点
		{
			dfs(v,u);
			son[u]+=son[v];
			dp[u]=max(dp[u],son[v]);//与u的各个子树节点比较
		}
	}
	dp[u]=max(dp[u],n-son[u]);//u最大的子树节点数与其父节点的子树节点数比较
    mins=min(mins,dp[u]);
}

int main()
{
	cin>>n;
	for(int i=1;i<n;i++)
	{
		int x,y;
		cin>>x>>y;
		add(x,y);
		add(y,x);
	}
	dfs(1,0);
	for(int i=1;i<=n;i++)
	{
		if(dp[i]==mins)
		{
		    cout<<"节点编号: "<<i<<endl;
		}
	}
}

输出:

节点编号: 1
节点编号: 2

二,vector

#include <iostream>
#include <vector>
#include <cstring>
using namespace std;

bool visit[205];//判断是否访问过
struct edge
{
	vector<int> v;
}e[205];

int ans[205],n,minm=1e9,dp[205];
//ans存子树节点数
//minm存最小的最大节点数
//dp存某个节点的子树的最大节点数
void dfs(int u)
{
	visit[u]=true;
	ans[u]=1;
	for(vector<int>::iterator it=e[u].v.begin();it!=e[u].v.end();it++)//逐一遍历u的子节点
	{
		int to=*it;
		if(!visit[to])
		{
		
			visit[to]=true;
			dfs(to);
			ans[u]+=ans[to];//逐一加上子节点的的节点数
			dp[u]=max(dp[u],ans[to]);
			visit[to]=false;//回溯
		}

	}
	dp[u]=max(dp[u],n-ans[u]);
	minm=min(dp[u],minm);
}

int main()
{

		memset(visit,false,sizeof visit);
		memset(ans,0,sizeof ans);
		cin>>n;
		for(int i=1;i<n;i++)
		{
			int x,y;
			cin>>x>>y;
			e[x].v.push_back(y);
			e[y].v.push_back(x);
		}
		dfs(1);
		for(int i=1;i<=n;i++)
		{
			if(dp[i]==minm)
			cout<<"节点编号: "<<i<<endl;
		}
	
}