poj 1655

参考杜宇飞神牛~http://hi.baidu.com/billdu/blog/item/6ef3e5029ce7d586d43f7cdb.html

题目大意:给一个树,删除其中一个点就会形成一个森林,点的平衡度为删除了这个节点后,所形成多个树,其中组成树的节点最多,节点个数就是那个平衡度。

要你求出最小平衡度,输出这个节点和平衡度,要是有多个节点的平衡度一样,输出节点序号最小。

解题思路,树形dp

balance[i]表示i结点的平衡度

balance[i] = max(node(k)), node(k)表示以i的孩子结点k为根的子树的总结点个数, 其中i为整棵树的根结点

可以规定节点1为这棵树的根结点,进行深度遍历,那么就形成了一个有向树, 在深度遍历的过程中,求出每个结点的出度,根据出度进行拓扑排序,将出度为0的点入队列

深度遍历的过程中求出以每个结点为根的子树的总个数node[k],blanance[k]初始化为num - node[k](num为整棵树的总结点个数)

遍历完毕后,按拓扑排序求balance[i] = max(node[k],balance[i]) ,k为i的孩子结点

 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;

struct nodes
{
    int u, next;
};

const int maxn = 20010;

int t, e, num, node[maxn], n, parent[maxn], balance[maxn], degree[maxn], head[maxn];
nodes edge[maxn*10];
queue<int> q;

void addEdge(int u, int v);
void dfs(int u, int pre);

int main()
{
    scanf("%d", &t);
    while(t-- != 0)
    {
        memset(node, 0, sizeof(node));
        memset(balance, 0, sizeof(balance));
        memset(degree, 0, sizeof(degree));
        memset(head, -1, sizeof(head));
        e = 0;
        while(!q.empty())
            q.pop();
        scanf("%d", &num);
        for(int i = 0; i < num - 1; i++)
        {
            int u, v;
            scanf("%d %d", &u, &v);
            addEdge(u, v);
        }
        int ans = 0x7fffffff, tnode;
        dfs(1, -1);
        while(!q.empty())
        {
            int u = q.front();
            q.pop();
            if(ans > balance[u])
            {
                ans = balance[u];
                tnode = u;
            }
            else if(ans == balance[u])
                tnode = min(tnode, u);
            if(parent[u] != -1)
            {
                balance[parent[u]] = max(balance[parent[u]], node[u]);
                degree[parent[u]]--;
                if(degree[parent[u]] == 0)
                    q.push(parent[u]);
            }
        }
       
        printf("%d %d\n", tnode, ans);
    }
   
    return 0;
}

void addEdge(int u, int v)
{
    edge[e].u = v;
    edge[e].next = head[u];
    head[u] = e++;
    
    edge[e].u = u;
    edge[e].next = head[v];
    head[v] = e++;
}

void dfs(int u, int pre)
{
    parent[u] = pre;
    node[u] = 1;
    if(pre != -1)
        degree[pre]++;
    for(int i = head[u]; i != -1; i = edge[i].next)
    {
        int v = edge[i].u;
        if(v != pre)
        {
            dfs(v, u);
            node[u] += node[v];
        }
    }
    balance[u] = num - node[u];
    if(degree[u] == 0)
        q.push(u);
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值