hdu3586
题目
就是给你一棵树,1节点是指挥部,叶子节点是前线士兵,每条边除去有代价,但代价的总和要小于上限m,现要让指挥部和叶子节点失去联系,要使删去的边中最大的最小,问这个最小值是多少。
思路
首先要想到这是一个二分判定性问题,二分上限值,用树形dp进行可行性判断dp[i]表示选i节点花费的最小代价的总和,dp[i]要么加上和子节点相连的那条边,或者是子节点的dp,注意子节点要赋成inf,且wa的可能是inf太大了。。。(竟然二分都要不会写了23333)
代码
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#include <iostream>
#include <stack>
#include <queue>
using namespace std;
typedef long long ll;
const int maxn=1100;
const int maxm=1000100;
int tot,head[maxn],n,m;
struct node
{
int next;
int to;
int w;
} edge[maxn*2];
void addedge(int from,int to,int w)
{
edge[tot].to=to;
edge[tot].next=head[from];
edge[tot].w=w;
head[from]=tot++;
}
int dp[maxn];
int lim;
void dfs(int u,int fa)
{
int cnt=0;
dp[u]=0;
for(int i=head[u]; ~i; i=edge[i].next)
{
int v=edge[i].to;
int w=edge[i].w;
if(v==fa) continue;
cnt++;
dfs(v,u);
if(w<=lim)
dp[u]+=min(w,dp[v]);
else
{
dp[u]+=dp[v];
}
}
if(cnt==0)
{
dp[u]=maxm;
}
}
int solve()
{
memset(dp,0,sizeof(dp));
dfs(1,-1);
if(dp[1]>m) return 0;
return 1;
}
int main()
{
while(scanf("%d %d",&n,&m)!=EOF)
{
if(n==0&&m==0) break;
int maxe=0;
memset(head,-1,sizeof(head));
tot=0;
for(int i=0; i<n-1; i++)
{
int a,b,c;
scanf("%d %d %d",&a,&b,&c);
addedge(a,b,c);
addedge(b,a,c);
maxe=max(maxe,c);
}
int l=1;
int r=maxe;
int mid=(l+r)>>1;
int ans=maxm;
while(l<=r)
{
mid=(l+r)>>1;
lim=mid;
if(solve())
{
r=mid-1;
ans=mid;
}
else
l=mid+1;
}
if(ans==maxm)
printf("-1\n");
else
printf("%d\n",ans);
}
return 0;
}