hdu3586 Information Disturbing 树形DP+二分

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3586

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

思路:很容易想到DP,定义dp[root]表示以root为根节点的子树失去与其叶子节点的链接的最小花费,那么如果其与孩子的边权小于limit,则dp[root]+=min(dp[son],w)(son为root的孩子,w为相连的边的权值),否则的话,dp[root]+=dp[son];

那么怎样确定limit值呢,由于问题是求使总花费不超过m的最小的limit值,当然就是二分答案了,确定limit的值的下限为1,上限为最大的边值,然后对于limit进行二分查找,如果最后求的总的花费值小于等于m,则往前找,否则就往后找。

代码如下:

 1 #include<cstdlib>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<iostream>
 5 using namespace std;
 6 #define MAX 1010
 7 #define INF 1000010
 8 class node
 9 {
10     public:
11     int to;
12     int w;
13     int next;
14 };
15 node edge[2*MAX];
16 int head[MAX];
17 int n,m;
18 int tol;
19 int dp[MAX];
20 int vis[MAX];
21 void init()
22 {
23    tol=0;
24    memset(head,-1,sizeof(head));
25 }
26 void Build_Tree(int u,int v,int w)
27 {
28     edge[tol].to=v;
29     edge[tol].w=w;
30     edge[tol].next=head[u];
31     head[u]=tol++;
32 }
33 int low,high,mid;
34 void dfs(int root,int pre)
35 {
36   vis[root]=1;
37   int flag=0;
38   for(int i=head[root];i!=-1;i=edge[i].next)
39     {
40        if(vis[edge[i].to]) continue;
41        flag=1;
42        int cost=edge[i].w;
43        int son=edge[i].to;
44        dfs(son,root);
45        if(cost<=mid) dp[root]+=min(dp[son],cost);
46        else dp[root]+=dp[son];
47     }
48     if(flag==0) dp[root]=INF;
49 }
50 int main()
51 {
52         while(scanf("%d%d",&n,&m)!=EOF)
53         {
54            init();
55            if(n==0&&m==0) break;
56            low=1;high=0;
57   
58           for(int i=1;i<n;i++)
59           {
60               int u,v,w;
61               scanf("%d%d%d",&u,&v,&w);
62               if(high<w) high=w; 
63               Build_Tree(u,v,w);
64               Build_Tree(v,u,w);
65           }
66           int ans=-1;
67         while(low<=high)
68         {
69           memset(dp,0,sizeof(dp));
70           memset(vis,0,sizeof(vis));
71           mid=(low+high)/2;
72           dfs(1,-1);
73           if(dp[1]>m) low=mid+1;
74           else {high=mid-1;ans=mid;}
75         }
76         cout<<ans<<endl;
77        }
78        return 0;
79 }
View Code