hdu 1011 Starship Troopers 树形dp

本文详细介绍了如何使用背包算法解决HDU 1011问题,包括理解题意、状态转移方程设计及代码实现等关键步骤。通过实例解析,帮助读者掌握该类型问题的解决方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://acm.hdu.edu.cn/showproblem.php?pid=1011

题意很纠结。。 第一遍看了题目之后以为是从根走到叶子结点不分叉,一交WA 。 再看题目,发现只是说同一个结点不能经过两次,但是可以“兵分几路”的思想去达到最大值。然后就是想到了对每个根结点u ,进行一次背包,但是这里还有一个地方需要注意,就是:如果要获得子结点的Brain 就必须要首先获得父节点的Brain,若不是这样的话,样例的最大值就应该是80 了。 由此得出状态转移方程: dp[u][j]:以u为根的子树中,用掉j个士兵时可以达到的最大值, dp[u][j] = max( dp[u][j] , dp[u][j - k]+dp[ son[u] ][k]  ) ;

代码:

#include<stdio.h>
#include<string.h>
#include<vector>
#define MAX(a,b) (a)>(b)?(a):(b)
using namespace std;
int N , M ;
int W[110] , V[110] ;
vector<int> G[110] ;
int f[110] ;
int dp[110][110] ;

void Build(int u){
	for(int i=0;i<G[u].size();i++){
		int v = G[u][i] ;
		if(v == f[u])	continue ;
		f[v] = u ;
		Build(v) ;	
	}	
}
void DP(int u){
	for(int i=0;i<G[u].size();i++){
		int v = G[u][i] ;
		if(v == f[u])	continue ;
		DP(v) ;
		for(int j=M ;j>=W[u];j--){
			for(int k=1;k+W[u]<=j;k++){	
				int temp = dp[u][j-k] + dp[v][k] ;
				if(dp[u][j] < temp){
					dp[u][j] = temp ;	
				}
			}
		}
	}
}
int main(){
	int a, b ;
	while(scanf("%d%d",&N,&M) == 2){
		if(-1==N && M==-1)	break ;
		memset(dp, 0 ,sizeof(dp));
		for(int i=1;i<=N;i++){
			scanf("%d%d",&a,&b);	
			W[i] = a/20 ; V[i] = b ;
			if(W[i]*20<a)	W[i]++ ;
			for(int j=W[i];j<=M;j++){
				dp[i][j] = V[i] ;
			}
		}		
		for(int i=1;i<=N;i++){
			G[i].clear();	
			f[i] = -1 ;
		}
		for(int i=1;i<N;i++){
			scanf("%d%d",&a,&b);	
			G[a].push_back(b); 
			G[b].push_back(a);
		}
		if(M==0){			//必须有,因为每个结点至少需要一个士兵,即使不需要代价也是。
			puts("0");	continue ;	
		}
		Build(1);			//建树
		DP(1) ;
		printf("%d\n",dp[1][M]);
	}	
	return 0; 	
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值