【dp每一天】POJ - 3107 Godfather (樹形dp)

額這題也挺水的。

題意:找樹上滿足去掉它之後,剩餘連通的結點塊中最大的那一塊最小的結點們。

思路:有 dp[u] = max(sum[v], n - sum[u]); v是u的子結點

代碼:

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

using namespace std;

const int maxn = 5e4 + 10,maxe = maxn * 2;
const int inf = 0x3f3f3f3f;
struct node
{
    int to,next;
    node(){}
    node(int a,int b){to = a ; next = b;}
}edge[maxe];
int h[maxn],sum[maxn];
int num,n,anum;
int ans[maxn];int vans = inf;
void init()
{
    for(int i = 0; i <= n; i++)
        h[i] = -1, sum[i] = 0;
    num = 0;    anum = 0;   vans = inf;
}
void add(int u,int v)
{
    edge[num] = node(v,h[u]);
    h[u] = num++;
}

void solve(int u,int pre)
{
    int res = 0,cnt = 0;
    for(int i = h[u] ;~i ; i = edge[i].next)
    {
        int v = edge[i].to;
        if(v == pre) continue;
        solve(v,u);
        cnt += sum[v];
        res = max(sum[v],res);
    }
    sum[u] = cnt + 1;
    res = max(res,n-sum[u]);
    if(res < vans)
    {
        anum = 0;
        vans = res;
        ans[anum++] = u;
    }
    else if(res == vans)
        ans[anum++] = u;
}
int main()
{
    while(~scanf("%d",&n))
    {
        init();
        int a,b;
        for(int i = 0; i < n-1; i++)
        {
            scanf("%d%d",&a,&b);
            add(a,b);   add(b,a);
        }
        solve(1,-1);
        sort(ans,ans+anum);
        for(int i = 0; i < anum; i++)
            i==0?printf("%d",ans[i]) : printf(" %d",ans[i]);
        printf("\n");
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章