题意:给n个节点的树,要求使叶子节点与根断开,割掉的边的权值和不超过m。求这些被割边的权值最大中的最小。
dp 【u】+=min(dp【v】,w),w 为 u 到 v 的权值。
如果w 大于二分的 mid dp【u】+=dp【v】;
二分枚举边权。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
using namespace std;
#define FF freopen("Input.txt","r",stdin)
#define ll long long
#define inf 1000020
const int N=1010;
int head[N];
struct Point
{
int v,w;
int next;
}edge[N*2];
int tot;
inline void init()
{
memset(head,-1,sizeof(head));
tot=0;
}
void add(int u,int v,int w)
{
edge[tot].v=v;
edge[tot].w=w;
edge[tot].next=head[u];
head[u]=tot++;
}
int dfs(int u,int k,int s)
{
int sum=0;
bool flag=false;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
int w=edge[i].w;
if(v==s) continue;
flag=true;
int tmp=dfs(v,k,u);
if(w<=k) sum+=min(tmp,w); //w 满足mid
else sum+=tmp; //不满足
}
if(!flag) sum=inf;
return sum;
}
int main()
{
//FF;
int n,i,m;
while(~scanf("%d%d",&n,&m))
{
if(n==0&&m==0) break;
init();
int l=1000000,r=0;
for(i=1;i<n;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c); add(b,a,c);
l=min(c,l);r=max(r,c); //l 和r记录边权的最小和最大值。
}
int ans=-1;
while(l<=r)
{
int mid=(l+r)>>1;
int sum=dfs(1,mid,0);
if(sum<=m) { ans=mid; r=mid-1;} //如果满足条件,更新答案。
else l=mid+1;
}
printf("%d\n",ans);
}
return 0;
}