HDOJ 3586 Information Disturbing(二分答案+树DP)

题意:给一棵带权有根树,边权表示切断此边的代价,现有一台切边的机器,但它有一个上限值up limited power,只能切断边权不超过up limited power的边,现要切断根节点与所有叶子结点的联系,总代价即为所切边的边权和,给定最大代价m,求最小的up limited power。

数据范围:n<=1000,m<=1000000,1<=边权wi<=1000

分析:二分答案,然后树DP判断。复杂度为O(NlogW)

View Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define N 1001
int n,m,e;
int first[N],next[N<<1],v[N<<1],w[N<<1],d[N];
int dp[N];
void init()
{
    e=0;
    memset(first+1,-1,sizeof(first[0])*n);
    memset(d+1,0,sizeof(d[0])*n);
}
void add(int a,int b,int c)
{
    d[a]++;
    v[e]=b;
    w[e]=c;
    next[e]=first[a];
    first[a]=e++;
}
void dfs(int a,int fa,int up)
{
    if(d[a]==1 && v[first[a]]==fa)
    {
        dp[a]=-1;
        return;
    }
    int i,b;
    for(i=first[a];~i;i=next[i])
    {
        b=v[i];
        if(b==fa)    continue;
        dfs(b,a,up);
        if(dp[a]==-1)   continue;
        if(dp[b]==-1 && w[i]>up)
        {
            dp[a]=-1;
        }
        else if(dp[b]!=-1 && w[i]<=up)
        {
            dp[a]+=min(w[i],dp[b]);
        }
        else if(dp[b]!=-1)
        {
            dp[a]+=dp[b];
        }
        else
        {
            dp[a]+=w[i];
        }
    }
}
bool judge(int up)
{
    memset(dp+1,0,sizeof(dp[0])*n);
    dfs(1,0,up);
    if(dp[1]<0 || dp[1]>m)  return 0;
    return 1;
}
int main()
{
    while(scanf("%d%d",&n,&m),(n|m))
    {
        if(n==1)
        {
            puts("0");
            continue;
        }
        int a,b,c,maxw=0;
        init();
        for(int i=1;i<n;i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            add(a,b,c);
            add(b,a,c);
            maxw=max(maxw,c);
        }
        if(judge(maxw)==0)
        {
            puts("-1");
            continue;
        }
        a=0,b=maxw;
        while(a+1!=b)
        {
            c=a+b>>1;
            if(judge(c))    b=c;
            else    a=c;
        }
        printf("%d\n",b);
    }
    return 0;
}
posted @ 2012-09-16 11:45  BeatLJ  阅读(199)  评论(0编辑  收藏  举报