hdu3586(树形DP+二分答案)

来源:互联网 发布:软考程序员考试题目 编辑:程序博客网 时间:2024/05/19 12:18

Information Disturbing

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)
Total Submission(s): 1085    Accepted Submission(s): 396


Problem Description
In the battlefield , an effective way to defeat enemies is to break their communication system.
The information department told you that there are n enemy soldiers and their network which have n-1 communication routes can cover all of their soldiers. Information can exchange between any two soldiers by the communication routes. The number 1 soldier is the total commander and other soldiers who have only one neighbour is the frontline soldier.
Your boss zzn ordered you to cut off some routes to make any frontline soldiers in the network cannot reflect the information they collect from the battlefield to the total commander( number 1 soldier).
There is a kind of device who can choose some routes to cut off . But the cost (w) of any route you choose to cut off can’t be more than the device’s upper limit power. And the sum of the cost can’t be more than the device’s life m.
Now please minimize the upper limit power of your device to finish your task.
 

Input
The input consists of several test cases.
The first line of each test case contains 2 integers: n(n<=1000)m(m<=1000000).
Each of the following N-1 lines is of the form:
ai bi wi
It means there’s one route from ai to bi(undirected) and it takes wi cost to cut off the route with the device.
(1<=ai,bi<=n,1<=wi<=1000)
The input ends with n=m=0.
 

Output
Each case should output one integer, the minimal possible upper limit power of your device to finish your task.
If there is no way to finish the task, output -1.
 

Sample Input
5 51 3 21 4 33 5 54 2 60 0
 

Sample Output
3
 

Author
alpc86
 
本题要求去掉若干单个权值不超过limit且这些边加起来权值不超过sum的边后能够切断根节点与所有叶节点的联系,求最小的limit
首先得选择limit,可以枚举,枚举过程中用二分法加速;选若干边旧的动态规划了,树形DP
            假设当前节点u为叶节点,令dp[u]=无穷大;
            若当前节点u为非叶节点:
                                                      当len[u][v]<=limit时,dp[u]=∑(dp[v],len[u][v]),其中v为该节点的孩子节点
                                                     当len[u][v]>limit时,dp[u]+=dp[v]
 
本题之所以转载大牛的,主要是应为他的邻接表实现的很好,比我的优化很多,建议构建无向图时用这个模板
 
/*HDU 3586树形DP+二分答案*/#include<stdio.h>#include<string.h>#include<iostream>#include<algorithm>using namespace std;const int MAXN=1010;const int INF=1000010;//这里一定要设得合适,不能太大,不能太小struct Node{    int to;    int next;    int w;}edge[MAXN*2];//存放边信息int head[MAXN];//存放节点信息,邻接表的简易实现方案int tol;int dp[MAXN];int min(int a,int b){return a<b?a:b;}void add(int a,int b,int w)//建立无向边函数{    edge[tol].to=a;    edge[tol].next=head[b];    edge[tol].w=w;    head[b]=tol++;    edge[tol].to=b;    edge[tol].next=head[a];    edge[tol].w=w;    head[a]=tol++;}void init()//初始化函数{    tol=0;    memset(head,-1,sizeof(head));}void dfs(int u,int pre,int limit)//树形DP的主要实现函数,一般树形DP都用DFS{    int i,flag=false;//标记是不是叶子结点    dp[u]=0;    for(i=head[u];i!=-1;i=edge[i].next)    {        int v=edge[i].to;//指向一个孩子节点        if(v==pre)continue;//由于是无向边,需排除指向父亲节点的那条边        flag=true;        dfs(v,u,limit);        if(edge[i].w<=limit)dp[u]+=min(dp[v],edge[i].w);//该边权值小于等于上限,可以尝试选择,只需选择子树到叶节点的路径上已选定的最小边与该节点到子树的边这二者中较小的那个        else dp[u]+=dp[v];//该边权值大于上限,不能选择,只能选择子树到叶节点的路径上已选定的最小边    }    if(!flag)dp[u]=INF;//叶子结点无穷大}int main(){    int n,m,i;    int a,b,w;    int l,r,mid;    while(scanf("%d%d",&n,&m)==2)    {        if(n==0&&m==0)break;        init();        r=0;        for(i=1;i<n;i++)        {            scanf("%d%d%d",&a,&b,&w);            add(a,b,w);            if(w>r)r=w;        }        l=1;        int ans=-1;        while(l<=r)        {            mid=(l+r)/2;            dfs(1,-1,mid);            if(dp[1]<=m)            {                ans=mid;                r=mid-1;            }            else l=mid+1;        }        printf("%d\n",ans);    }    return 0;}