Information Disturbing HDU - 3586(树形DP,有限制的割边, 二分)

Information Disturbing

 题目链接:HDU - 3586

题意:敌军有一队侦察兵,每个通讯兵只与他的直接上级单线联系,队长是1号,通讯系统构成树状结构;现,总军司令要求你切断先锋通讯兵(叶子节点)与总队长(根节点)的联系,并且消耗体力不能超过m;求出满足条件的每次切断一条边的最大体力消耗值;

思路:不看切边的限制,就是一个落得树形DP,加上限制后只不过改了状态转移方程;

不加限制时的状态转移方程:dp[u]=\summin(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;
}

猜你喜欢

转载自blog.csdn.net/Sirius_han/article/details/81301711