HDU-3586 Information Disturbing(树形DP+删边)

题目大意:一棵有n个节点的有根树,1为根节点,边带权,表示删掉这条边的代价。现在要删掉一些边,使叶子节点不能到达根节点。但是,每次删除的边的代价不能超过limit,删掉的边的总代价不能超过m,求最小的limit的可能取值。

题目分析:二分枚举limit,定义状态dp(u)表示将u与它管辖的叶子节点失去联系所需要的总代价,则:

dp(u)+=min(dp(son),e[i].w),e[i].w<=limit;

dp(u)+=dp(son)  e[i].w>limit;

代码如下:

# include<iostream>
# include<cstdio>
# include<cstring>
# include<vector>
# include<queue>
# include<list>
# include<set>
# include<map>
# include<string>
# include<cmath>
# include<cstdlib>
# include<algorithm>
using namespace std;
# define LL long long

const int N=1005;
const int INF=1000001;

struct Edge
{
	int w,to,nxt;
};
Edge e[N];
int n,m;
int du[N];
int maxn,cnt;
int dp[N];
int head[N];

void add(int u,int v,int w)
{
	e[cnt].to=v;
	e[cnt].w=w;
	e[cnt].nxt=head[u];
	head[u]=cnt++;
}

void init()
{
	int a,b,c;
	cnt=maxn=0;
	memset(du,0,sizeof(du));
	memset(head,-1,sizeof(head));
	for(int i=1;i<n;++i){
		scanf("%d%d%d",&a,&b,&c);
		++du[a];
		++du[b];
		maxn=max(maxn,c);
		add(a,b,c);
		add(b,a,c);
	}
}

void dfs(int u,int fa,int limit)
{
	//cout<<u<<endl;
	if(du[u]==1&&u!=1){
		dp[u]=INF;
		return ;
	}
	dp[u]=0;
	for(int i=head[u];i!=-1;i=e[i].nxt){
		int v=e[i].to;
		if(v==fa) continue;
		dfs(v,u,limit);
		if(e[i].w>limit)
			dp[u]+=dp[v];
		else
			dp[u]+=min(dp[v],e[i].w);
	}
}

int solve()
{
	if(n==1)
		return 0;
	int l=1,r=maxn+1;
	while(l<r){
		int mid=l+(r-l)/2;
		dfs(1,-1,mid);
		if(dp[1]>m)
			l=mid+1;
		else
			r=mid;
	}
	dfs(1,-1,r);
	if(dp[1]>m) return -1;
	return r;
}

int main()
{
	//新的主题
	while(~scanf("%d%d",&n,&m)&&(n+m))
	{
		init();
		printf("%d
",solve());
	}
	return 0;
}

  

原文地址:https://www.cnblogs.com/20143605--pcx/p/5373121.html