Hdu 3586 Information Disturbing (DP_树形DP)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3586


题目大意:给定n个敌方据点,1为司令部,其他点各有一条边相连构成一棵树,每条边都有一个权值cost表示破坏这条边的费用,叶子节点为前线。现要切断前线和司令部的联系,每次切断边的费用不能超过上限limit,问切断所有前线与司令部联系所花费的总费用少于m时的最小limit。1<=n<=1000,1<=m<=100万


解题思路:一看到题目就觉得是树形DP,男人的第六感怎一个准字了得。然后努力地把题目看懂了以后,发现这是一个判定性问题,就是问某个limit是否能够满足条件切断所有前线与司令部的联系,然后找符合条件的最大limit就可以了。想通这点以后就可以二分答案,下限为1,上限为最大的边权,再写一个Tree_DP(limit),判断切断所有前线联系时花费的最小费用是否小等于m,是的话就往后查找,否则向前。

    设dp[i]为切断i的所有子孙叶子所花费的最小费用,状态转移方程: if (i->son.len < limit) dp[i] += min(dp[i->son],i->son.len); (如果与子节点相连的边可选)

                                                                                                          else dp[i]  += dp[i->son];(如果与子节点相连的边不可选)


测试数据:

4 2
1 2 3
2 3 1
2 4 1

5 5
1 3 2
1 4 3
3 5 5
4 2 6

5 10
1 3 5
1 4 5
3 5 5
4 2 5

5 5
1 2 5
2 3 5
2 4 5
3 5 5

2 1
1 2 1


代码:

#include <stdio.h>
#include <string.h>
#define MIN 1100
#define MAX 2100
#define INF 1000001
#define min(a,b) (a)<(b)?(a):(b)


struct node {

	int v,len;
	node *next;
}*head[MAX],tree[MAX];
int n,m,dp[MIN];
int high,low,mid,len;
int ptr,vis[MIN],ans;


void Initial() {

	ans = INF,len = 0,ptr = 1;
	memset(head,NULL,sizeof(head));
}
void AddEdge(int a,int b,int c) {

	tree[ptr].v = b,tree[ptr].len = c;
	tree[ptr].next = head[a],head[a] = &tree[ptr++];
	tree[ptr].v = a,tree[ptr].len = c;
	tree[ptr].next = head[b],head[b] = &tree[ptr++];
}
void Tree_DP(int v,int maxx) {

	if (vis[v]) return;
	vis[v] = 1;


	int i,j,k,tpk;
	node *p = head[v];
	int tot = 0,flag = 0;


	while (p != NULL) {

		if (!vis[p->v]) {

			flag = 1;
			Tree_DP(p->v,maxx);
			if (p->len > maxx) tot += dp[p->v];
			else tot += min(dp[p->v],p->len);	
		}
		p = p->next;
	}
	if (flag) dp[v] = tot;
	else dp[v] = INF;
}


int main()
{
	int i,j,k,a,b,c;


	while (scanf("%d%d",&n,&m),n+m) {

		Initial();
		for (i = 1; i < n; ++i) {

			scanf("%d%d%d",&a,&b,&c);
			AddEdge(a,b,c);
			if (c > len) len = c;
		}


		low = 1,high = len;
		while (low <= high) {

			for (i = 0; i <= n; ++i)
				dp[i] = vis[i] = 0;
			mid = low + (high - low)/2;


			Tree_DP(1,mid);
			if (dp[1] <= m) {
				
				ans  = mid;
				high = mid - 1;
			}
			else low = mid + 1;
		}


		if (ans == INF) printf("-1\n");
		else printf("%d\n",ans);
	}
	return 0;
}

本文ZeroClock原创,但可以转载,因为我们是兄弟。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值