您的位置:首页 > 编程语言 > Go语言

【求树的重心】POJ - 3107 Godfather

2017-06-17 09:55 323 查看
Problem Description

输入n,代表有n个编号1-n的结点。接下来有n行,每行输入u,v分别表示u,v有联系。让你找出Godfather,其实就是找出树的重心,如果有多个满足这样的点,从小到大输出。

思路:第一次做,所以是去网上学习的方法,发现他们都归类为树形dp,然而我dp可能有点差,理解了代码但是没能理解为何是dp。具体的解释看代码里面的注释,,,树的重心(找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心,删去重心后,生成的多棵树尽可能平衡。)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node
{
int to, next;
};
node e[100000];
//e,head是前向星存图用的数组。n个结点,ans[]用来记录最后结果,vis[]用来标记那些点跑过,Size[]用来记录它的子数的结点数,n-size[]对应的就是父亲那边的结点数。
int head[100000], n, ans[50005], vis[50005], Size[50005], m, top;
void dfs(int u)//dfs遍历所有结点
{
int v;
vis[u] = 1;//标记已经走过
Size[u] = 1;//走到的结点初始化为1
int t = 0;//用来存储孩子最大的Size
for(int i = head[u]; ~i; i = e[i].next)
{
v = e[i].to;
if(!vis[v])//没有走过的结点
{
dfs(v);
Size[u] += Size[v];//回潮的时候,更新父亲结点的Size
t = max(t, Size[v]);//更新t的大小
}
}
t = max(t, n - Size[u]);//求孩子Size,和本身Size最大的
if(t < m)//更新树的重心所有子数,最大子树的结点,存入结果
{
top = 0;
m = t;
ans[top++] = u;
}
else if(t == m)//多个重心
{
ans[top++] = u;
}
}
int main()
{
int u, v;
while(~scanf("%d", &n))
{
m = n;
memset(head, -1, sizeof(head));//初始化
memset(vis, 0, sizeof(vis));
memset(Size, 0, sizeof(Size));
int cnt = 0;
for(int i = 0; i < n - 1; i++)//前向星存图
{
scanf("%d %d", &u, &v);
e[cnt].to = v;
e[cnt].next = head[u];
head[u] = cnt++;
e[cnt].to = u;
e[cnt].next = head[v];
head[v] = cnt++;
}
dfs(1);//求树的重心
sort(ans, ans + top);//排序
for(int i = 0; i < top; i++)//输出
{
if(i) printf(" ");
printf("%d", ans[i]);
}
printf("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  poj dp