您的位置:首页 > 其它

POJ 1655 Balancing Act 树的重心

2015-01-23 09:38 260 查看
题意:给出一颗树,求树的重心:删除该点后,形成的森林中每个子树的节点数量的最大值最小。

思路:因为题目中给出的是无向、无根的树,我们可以先将他有根、有向化。考虑一个节点,将该节点删除后,会将该点和所有孩子的边删除,同时删除的是该点和父亲的边。

这样产生的森林就分成了两个部分,第一部分是由该节点的子树形成,所以我们要求出子树中节点的最大值。第二部分是由父亲节点形成的树,这一部分的节点是无法直接求出来的,但是我们可以用所有的节点的数目减去以该点为根的子树的所有节点的和。

最后,我们在线性的扫一遍就能得到最后的结果。

代码如下:

#include <cstdio>
#include <algorithm>
#include <cstring>

using namespace std;

const int MAXN = 20010;
const int MAXM = 2 * MAXN;

struct edge{
int from,to;
edge(){}
edge(int u, int v):from(u),to(v){}
};

int head[MAXN],nxt[MAXM],tot;
edge edges[MAXM];
int N,M;
int sc[MAXN],mc[MAXN];

void init()
{
memset(head,-1,sizeof(head));
tot = 0;
}
void addedge(int u, int v)
{
edges[tot] = edge(u,v);
nxt[tot] = head[u], head[u] = tot++;
edges[tot] = edge(v,u);
nxt[tot] = head[v], head[v] = tot++;
}

int dfs(int u, int pre)
{
sc[u] = 1, mc[u] = 0;
for(int i = head[u]; ~i; i = nxt[i]){
edge &e = edges[i];
if(e.to != pre){
int t = dfs(e.to,u);
sc[u] += t;
mc[u] = max(mc[u],t);
}
}
return sc[u];
}

int main(void)
{
//freopen("input.txt","r",stdin);
int T;
scanf("%d",&T);
while(T--){
scanf("%d",&N);
init();
for(int i = 0; i < N - 1; ++i){
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v);
}
dfs(1,0);
int ans = 0x3f3f3f3f,pos;
for(int i = 1; i <= N; ++i){
int t = max(N - sc[i],mc[i]);
if(t < ans){
ans = t;
pos = i;
}
}
printf("%d %d\n",pos,ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: