【树形DP】HDU 3586 Information Disturbing

通道:http://acm.hdu.edu.cn/showproblem.php?pid=3586

题意:给定n个敌方据点,1为司令部,其他点各有一条边相连构成一棵树,每条边都有一个权值cost表示破坏这条边的费用,叶子节点为前线。现要切断前线和司令部的联系,每次切断边的费用不能超过上限limit,问切断所有前线与司令部联系所花费的总费用少于m时的最小limit

思路:对于上限进行二分,然后通过树形DP进行判断,dp[i]为切断i的所有子孙叶子所花费的最小费用,状态转移方程: if (i->son.len < limit) dp[i] += min(dp[i->son],i->son.len); 

代码:

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

using namespace std;

const int VM=1010;
const int INF=1000010;  //开始设为0x3f3f3f3f给了WA

struct Edge{
    int to,nxt;
    int cap;
}edge[VM<<1];

int n,m,cnt,head[VM];
int dp[VM],vis[VM];

void addedge(int cu,int cv,int cw){
    edge[cnt].to=cv;
    edge[cnt].cap=cw;
    edge[cnt].nxt=head[cu];
    head[cu]=cnt++;
}

void DFS(int u,int pre,int lim){
    int flag=0; //标记是不是叶子结点
    dp[u]=0;
    for(int i=head[u];i!=-1;i=edge[i].nxt){
        int v=edge[i].to;
        if(v!=pre){
            flag=1;
            DFS(v,u,lim);
            if(edge[i].cap<=lim)
                dp[u]+=min(dp[v],edge[i].cap);
            else
                dp[u]+=dp[v];
        }
    }   
    if(!flag)   //叶子结点无穷大
        dp[u]=INF;
}

int main(){

    //freopen("input.txt","r",stdin);

    while(~scanf("%d%d",&n,&m)){
        if(n==0 && m==0)
            break;
        cnt=0;
        memset(head,-1,sizeof(head));
        int MAX=0;
        int u,v,w;
        for(int i=1;i<n;i++){
            scanf("%d%d%d",&u,&v,&w);
            addedge(u,v,w);
            addedge(v,u,w);
            if(w>MAX)
                MAX=w;
        }
        int l=1,r=MAX,ans=-1;
        while(l<=r){
            int mid=(l+r)>>1;
            DFS(1,-1,mid);
            if(dp[1]<=m){
                ans=mid;
                r=mid-1;
            }else
                l=mid+1;
        }
        printf("%d\n",ans);
    }
    return 0;
}
View Code

 

posted @ 2014-11-03 19:54  mithrilhan  阅读(206)  评论(0编辑  收藏  举报