题意:给出n个士兵,其中1号为指挥官,关系为树状结构,叶子为先锋,现在要在总花费小于m的情况切断所有的先锋与指挥官的联系,问最大的限制最小为多少
思路:最大值最小的问题..显然二分,然后对于每一个值,树形DP判定是否可行,dp[i]表示要切断以i为根的其它所有子树的最小代价。其中设定叶子结点的代价为无穷大,那么对于某一个非叶子结点,要切断一棵子树就有两种选择,切断以孩子为根的子树或者切断根与孩子的边。,如果根与孩子的边大于限制,那就取无穷大。最后判断1号结点的总花费是否小于等于m
注意:无穷大不要取太大,否则会连续相加溢出
#include <cstdio>
#include <queue>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <map>
#include <string>
#include <set>
#include <ctime>
#include <cmath>
#include <cctype>
using namespace std;
#define maxn 100005
#define inf 1<<20
#define LL long long
int cas=1,T;
int n,m;
struct Edge
{
int v,w;
Edge(int vv,int ww):v(vv),w(ww){}
};
vector<Edge>e[maxn];
int dp[maxn];
void dfs(int u,int fa,int limit)
{
int flag = 0;
dp[u]=0;
for (int i = 0;i<e[u].size();i++)
{
int v = e[u][i].v;
if (v==fa)
continue;
flag=1;
dfs(v,u,limit);
if (e[u][i].w<=limit)
dp[u]+=min(dp[v],e[u][i].w);
else
dp[u]+=dp[v];
}
if (!flag)
dp[u]=inf;
}
bool check(int mid)
{
memset(dp,0,sizeof(dp));
dfs(1,-1,mid);
if (dp[1]<=m)
return true;
return false;
}
int main()
{
while (scanf("%d%d",&n,&m)!=EOF && (n+m))
{
for (int i = 0;i<=n;i++)
e[i].clear();
int maxw=0;
for (int i = 1;i<n;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
e[u].push_back(Edge(v,w));
e[v].push_back(Edge(u,w));
maxw=max(maxw,w);
}
int l = 1,r=maxw;
int ans = -1;
while (l<=r)
{
int mid = (l+r)/2;
if (check(mid))
r=mid-1,ans=mid;
else
l=mid+1;
}
printf("%d\n",ans);
}
//freopen("in","r",stdin);
//scanf("%d",&T);
//printf("time=%.3lf",(double)clock()/CLOCKS_PER_SEC);
return 0;
}