您的位置:首页 > 其它

树的重心 poj - 1655 和 poj - 3107

2017-10-10 21:47 281 查看
首先知道 树的重心定义为: 找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心,删去重心后,生成的多棵树尽可能平衡. 实际上树的重心在树的点分治中有重要的作用, 可以避免N^2的极端复杂度(从退化链的一端出发),保证nlogn的复杂度, 利用树型dp可以很好地求树的重心.

poj - 1655

//题意: 就是求树的重心编号, 以及删除该点后节点数size, 如果size相同, 那么就选编号较小的那个.

//就是一道模板题, 直接dfs一遍树. 然后不断更新答案即可. 详情请看代码

AC Code

const int maxn = 2e4+5;
int cas=1,n;
int a[maxn];
int son[maxn];
int cnt,head[maxn];
struct node
{
int to,next;
}e[maxn*2];

void add(int u,int v)
{
e[cnt] = (node){v,head[u]};
head[u] = cnt++;
}
int ans ,siz;
void dfs(int u,int fa)
{
son[u] = 0;
int tmp = 0;
for(int i=head[u]; ~i ; i = e[i].next){
int to = e[i].to;
if(fa == to) continue;
dfs(to,u);
son[u] += son[to] + 1;
tmp = max(tmp,son[to]+1);
}
tmp = max(tmp,n - son[u] - 1);
if(tmp < siz || (tmp == siz && u > ans)) {
ans = u;
siz = tmp;
}
}
void solve()
{
while(~scanf("%d",&n)){
cnt = 0; Fill(head,-1);
Fill(son,0); ans = -1; siz = inf;
for(int i=1;i<n;i++){
int u,v; scanf("%d%d",&u,&v);
add(u,v); add(v,u);
}
dfs(1,-1);
printf("%d %d\n",ans,siz);
}
}


poj - 3107

//题意: 就是按升序输出所有的树的重心编号, 因为可能存在一些点, 使得删去他们后最大子树的节点数可能相等, 那么加一个判断即可.

AC Code

const int maxn = 5e4+5;
int cas=1,n;
int a[maxn];
int son[maxn],ans[maxn];
int cnt,head[maxn];
struct node
{
int to,next;
}e[maxn*2];

void add(int u,int v)
{
e[cnt] = (node){v,head[u]};
head[u] = cnt++;
}
int num ,siz;
void dfs(int u,int fa)
{
son[u] = 0;
int tmp = 0;
for(int i=head[u]; ~i ; i = e[i].next){
int to = e[i].to;
if(fa == to) continue;
dfs(to,u);
son[u] += son[to] + 1;
tmp = max(tmp,son[to]+1);
}
tmp = max(tmp,n - son[u] - 1);
if(tmp < siz){
siz = tmp;
num = 0;
ans[++num] = u;
}
else if(tmp == siz){
ans[++num] = u;
}
}

void solve()
{
while(~scanf("%d",&n)){
cnt = 0; Fill(head,-1);
Fill(son,0); siz = inf;
for(int i=1;i<n;i++){
int u,v; scanf("%d%d",&u,&v);
add(u,v); add(v,u);
}
dfs(1,-1);
sort(ans+1,ans+num+1);
for(int i=1;i<=num;i++){
printf("%d%c",ans[i],i==num?'\n':' ');
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: