题意:给一棵带权有根树,边权表示切断此边的代价,现有一台切边的机器,但它有一个上限值up limited power,只能切断边权不超过up limited power的边,现要切断根节点与所有叶子结点的联系,总代价即为所切边的边权和,给定最大代价m,求最小的up limited power。
数据范围:n<=1000,m<=1000000,1<=边权wi<=1000
分析:二分答案,然后树DP判断。复杂度为O(NlogW)
View Code
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define N 1001 int n,m,e; int first[N],next[N<<1],v[N<<1],w[N<<1],d[N]; int dp[N]; void init() { e=0; memset(first+1,-1,sizeof(first[0])*n); memset(d+1,0,sizeof(d[0])*n); } void add(int a,int b,int c) { d[a]++; v[e]=b; w[e]=c; next[e]=first[a]; first[a]=e++; } void dfs(int a,int fa,int up) { if(d[a]==1 && v[first[a]]==fa) { dp[a]=-1; return; } int i,b; for(i=first[a];~i;i=next[i]) { b=v[i]; if(b==fa) continue; dfs(b,a,up); if(dp[a]==-1) continue; if(dp[b]==-1 && w[i]>up) { dp[a]=-1; } else if(dp[b]!=-1 && w[i]<=up) { dp[a]+=min(w[i],dp[b]); } else if(dp[b]!=-1) { dp[a]+=dp[b]; } else { dp[a]+=w[i]; } } } bool judge(int up) { memset(dp+1,0,sizeof(dp[0])*n); dfs(1,0,up); if(dp[1]<0 || dp[1]>m) return 0; return 1; } int main() { while(scanf("%d%d",&n,&m),(n|m)) { if(n==1) { puts("0"); continue; } int a,b,c,maxw=0; init(); for(int i=1;i<n;i++) { scanf("%d%d%d",&a,&b,&c); add(a,b,c); add(b,a,c); maxw=max(maxw,c); } if(judge(maxw)==0) { puts("-1"); continue; } a=0,b=maxw; while(a+1!=b) { c=a+b>>1; if(judge(c)) b=c; else a=c; } printf("%d\n",b); } return 0; }