题意:
给你n点的树,每条边有权值
你可以任意选边切断,使得最后的所有原图中的叶子节点都不与1相连
这会花费切断边的权值cost,切断的边中 权值最大边 w
必须满足的是 cost不超过给定的m,且使得w尽量小
输出这个最小的w,没有满足条件的 -1
题解:
我们二分答案
对于得到limit,我们在树上选边切断的时候 保持被切断的边的权值不超过它就是了,每次DP处理即可
#include <iostream> #include <cstdio> #include <cmath> #include <cstring> #include<vector> #include <algorithm> using namespace std; const int N = 1e3+20, M = 1e2+10, mod = 1e9+7, inf = 1e9+1000; typedef long long ll; struct edge{int to,next,w;}e[N * 4]; int head[N] , t , n , m , cost, dp[N]; void add(int u,int v,int w) {e[t].to=v,e[t].w=w,e[t].next=head[u];head[u]=t++;} void init() {t=1;memset(head,-1,sizeof(head));} void dfs(int u,int fa,int limit) { int ret = 0, cnt = 0; for(int i=head[u];i!=-1;i=e[i].next) { int to = e[i].to; int value = e[i].w; if(to == fa) continue; cnt += 1; dfs(to,u,limit); if(dp[to] == -1) { if(value <= limit) ret += value; else return ; }else { if(value <= limit) ret += min(dp[to] , value); else ret += dp[to]; } } if(cnt)dp[u] = ret; } int check(int limit) { memset(dp,-1,sizeof(dp)); dfs(1,-1,limit); if(dp[1] == -1) return 0; else { cost = dp[1]; return 1; } } int main() { while(~scanf("%d%d",&n,&m)) { if(!n&&!m) break; int mx = 0; init(); for(int i=1;i<n;i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); mx = max(c,mx); add(a,b,c); add(b,a,c); } int l = 0, r = mx, ans = -1; while(l<=r) { int mid = (l+r) / 2; cost = 0; int OK = check(mid); if(OK && cost <= m) { r = mid - 1; ans = mid; }else { l = mid + 1; } } if(ans == -1) puts("-1"); else if(check(ans)&&cost <= m) cout<<ans<<endl; else puts("-1"); } }
HDU 3586 Information Disturbing 树形DP+二分
原文:http://www.cnblogs.com/zxhl/p/5689527.html