标签:
http://acm.hdu.edu.cn/showproblem.php?pid=3586
5 5 1 3 2 1 4 3 3 5 5 4 2 6 0 0
3
/** hdu 3586 树形dp二分求解 题目大意:给定一棵树n个点,点1是根节点,每个叶子节点都向根节点传递“消息”,我们要在一些路上阻止,使路径不通。每条路上的阻止代价为该路权值, 我们能阻止的权值有一个上限x,而且所有叶子节点阻止的代价和不能超过m。问最小的可行x 解题思路:假设我们已经到了一个x,那么以u为根节点的子树的总花费dp[u],若边权值w<=x,dp[u]+=min(dp[v],w),否则dp[u]+=min(dp[v],inf), 这里的inf为任意一个大于m的数(但注意不要爆掉int,我取的m+1)。解释一下为什么用inf,因为w值已经超过限制我们不能阻止w边了, 那么要阻止以v为根节点子树的所有叶子节点,只能是dp[v]了。这样树形dp就可以求出dp[1],和m比较即可知道我们的x值合不合适了。 对于x二分就可以了。 */ #include <stdio.h> #include <string.h> #include <algorithm> #include <iostream> using namespace std; const int maxn=1005; struct note { int v,w,next; }edge[maxn*2]; int head[maxn],ip; int n,m,mid,dp[maxn]; void init() { memset(head,-1,sizeof(head)); ip=0; } void addedge(int u,int v,int w) { edge[ip].v=v,edge[ip].w=w,edge[ip].next=head[u],head[u]=ip++; } void dfs(int u,int pre) { int flag=0; for(int i=head[u];i!=-1;i=edge[i].next)///求解父亲节点前它的所有儿子节点必须全部已经求出 { int v=edge[i].v; if(v==pre)continue; flag=1; dfs(v,u); } if(flag==0)///叶子节点 { dp[u]=m+1;///任意一个大于m的数 return; } int t=0; for(int i=head[u];i!=-1;i=edge[i].next) { int w=edge[i].w; int v=edge[i].v; if(v==pre)continue; if(w<=mid) dp[u]+=min(dp[v],w); else dp[u]+=min(dp[v],m+1); } } int main() { while(~scanf("%d%d",&n,&m)) { if(n==0&&m==0)break; int maxx=0; init(); for(int i=0;i<n-1;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); addedge(u,v,w); addedge(v,u,w); maxx+=w; } int l=1,r=maxx; int flag=0; while(l<r) { mid=(l+r)>>1; memset(dp,0,sizeof(dp)); dfs(1,-1); // printf("%d %d\n",mid,dp[1]); if(dp[1]<=m) { flag=1; r=mid; } else l=mid+1; } if(flag==0) printf("-1\n"); else printf("%d\n",r); } return 0; } /** 5 4 1 3 2 1 4 3 3 5 5 4 2 6 5 4 1 3 2 1 4 2 3 5 5 4 2 6 5 3 1 3 2 1 4 2 3 5 5 4 2 6 */
标签:
原文地址:http://blog.csdn.net/lvshubao1314/article/details/43739657