当前位置: 移动技术网 > IT编程>开发语言>.net > C. Link Cut Centroids(求树的重心)

C. Link Cut Centroids(求树的重心)

2020年09月01日  | 移动技术网IT编程  | 我要评论
https://codeforces.com/contest/1406/problem/C做这个题前提是要知道树的重心。百度拉了一下。引用一下:https://blog.csdn.net/weixin_43810158/article/details/88391828树的重心定义为树的某个节点,当去掉该节点后,树的各个连通分量中,节点数最多的连通分量其节点数达到最小值。树可能存在多个重心。如下图,当去掉点1后,树将分成两个连通块:(2,4,5),(3,6,7),则最大的连通块包含节点个数为3。若

https://codeforces.com/contest/1406/problem/C


做这个题前提是要知道树的重心。百度拉了一下。

引用一下:https://blog.csdn.net/weixin_43810158/article/details/88391828

树的重心定义为树的某个节点,当去掉该节点后,树的各个连通分量中,节点数最多的连通分量其节点数达到最小值。树可能存在多个重心。如下图,当去掉点1后,树将分成两个连通块:(2,4,5),(3,6,7),则最大的连通块包含节点个数为3。若去掉点2,则树将分成3个部分,(4),(5),(1,3,6,7)最大的连通块包含4个节点;第一种方法可以得到更小的最大联通分量。可以发现,其他方案不可能得到比3更小的值了。所以,点1是树的重心。

 

性质:

  1.删除重心后所得的所有子树,节点数不超过原树的1/2,一棵树最多有两个重心;

  2.树中所有节点到重心的距离之和最小,如果有两个重心,那么他们距离之和相等;

  3.两个树通过一条边合并,新的重心在原树两个重心的路径上;

  4.树删除或添加一个叶子节点,重心最多只移动一条边;

       5.一棵树最多有两个重心,且相邻。


思路:如果找到只有一个重心,那么直接删一个重心的直连边然后加回去就好了。

如果找到两个重心,那么在其中一个重心上找到一个直连点不是另一个重心,删除连另外一个就好了。

如何求树的重心?,

先任选一个结点作为根节点,把无根树变成有根树。然后设siz[i]表示以i为根节点的子树节点个数。转移为siz[i]=∑(siz[i的儿子节点] );

设son[i]表示删去节点x后剩下的连通分量中最大子树节点个数。其中一部分在原来i其为根的子树。son[i]=max(son[i],siz[i的儿子节点]);

另外一部分在i的“上方”子树有n-siz[i]个。  son[i]=max(son[i],n-siz[i]);

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=1e5+100;
typedef long long LL;
vector<LL>g[maxn]; 
LL siz[maxn],son[maxn];
LL r1,r2,n; 
void dfs(LL u,LL fa)
{
	siz[u]=1;
	son[u]=0;
	for(LL i=0;i<g[u].size();i++){
		LL v=g[u][i];
		if(v==fa) continue;
		dfs(v,u);
		siz[u]+=siz[v];
		son[u]=max(son[u],siz[v]);
	}
	son[u]=max(son[u],n-siz[u]);
	if((son[u]<<1)<=n) r2=r1,r1=u;
}
int main(void)
{
  cin.tie(0);std::ios::sync_with_stdio(false);
  LL t;cin>>t;
  while(t--){
  	cin>>n;
  	for(LL i=0;i<=n+10;i++) g[i].clear(),siz[i]=0,son[i]=0;
  	for(LL i=1;i<n;i++){
  		LL x,y;cin>>x>>y;
  		g[x].push_back(y);g[y].push_back(x);
	}
	r1=r2=0;
	dfs(1,0);
	if(!r2){
		LL r3=g[r1][0];
		cout<<r1<<" "<<r3<<endl;
		cout<<r1<<" "<<r3<<endl;
	}
	else{
		LL r3=r1;
	//	debug(r1);debug(r2);
		for(LL i=0;i<g[r2].size();i++){
			r3=g[r2][i];
		//	debug(r3);
			if(r3!=r1) break;
		}
		cout<<r3<<" "<<r2<<endl;
		cout<<r3<<" "<<r1<<endl;
	}
  }
return 0;
}

 

本文地址:https://blog.csdn.net/zstuyyyyccccbbbb/article/details/108558682

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网