Information Disturbing
题意:敌军有一队侦察兵,每个通讯兵只与他的直接上级单线联系,队长是1号,通讯系统构成树状结构;现,总军司令要求你切断先锋通讯兵(叶子节点)与总队长(根节点)的联系,并且消耗体力不能超过m;求出满足条件的每次切断一条边的最大体力消耗值;
思路:不看切边的限制,就是一个落得树形DP,加上限制后只不过改了状态转移方程;
不加限制时的状态转移方程:dp[u]=min(dp[son], wi) (son是u的儿子节点,wi是u与son的连边长度);
加上限制后的状态转移方程:
if(limit<w) dp[u]+=dp[son];
else dp[u]+=min(dp[son], wi);
但是怎么求这个最大的限制呢???
枚举????不行,
可以想象到,没有限制的时候消耗体力是最小的,限制是0的时候,无法完成任务,此时消耗最大;
所以可以用二分枚举限制;
#include <bits/stdc++.h>
using namespace std;
const int maxn=1010;
struct node{
int v, w, nxt;
node(){}
node(int v0, int w0, int n){
v=v0, w=w0, nxt=n;
}
}edge[maxn<<1];
int head[maxn], cnt;
void add(int u, int v, int w){
edge[cnt]=node(v, w, head[u]);
head[u]=cnt++;
}
int dp[maxn];
void dfs(int u, int fa, int limit){
dp[u]=0;
int flag=1;
for(int i=head[u]; i!=-1; i=edge[i].nxt){
int v=edge[i].v, w=edge[i].w;
if(v==fa) continue;
flag=0;
dfs(v, u, limit);
if(w<=limit) dp[u]+=min(dp[v], w);
else dp[u]+=dp[v];
if(dp[u]>=10000100) dp[u]=10000100;
}
if(flag) dp[u]=10000100;
}
int main(){
int n, m;
while(scanf("%d%d", &n, &m), n||m){
memset(head, -1, sizeof(head));
cnt=0;
for(int i=1; i<n; i++){
int a, b, w;
scanf("%d%d%d", &a, &b, &w);
add(a, b, w);
add(b, a, w);
}
int l=1, r=1000, ans=-1;
while(l<=r){
int mid=(l+r)>>1;
dfs(1, 1, mid);
int temp=dp[1];
if(temp>m) l=mid+1;
else r=mid-1, ans=mid;
}
printf("%d\n", ans);
}
return 0;
}