HDU 1011 Starship Troopers - 01树形dp 有坑啊!!

/*
	http://acm.hdu.edu.cn/showproblem.php?pid=1011 Starship Troopers
	01树形dp
	题意:多个舰队,攻打bug的洞穴,每一个洞穴里面有很多bug和一些brain,我们需要派一个舰队去获得更多的brain
	这个过程我们遵循:洞穴为一个树形结构(没有环),洞穴的入口为1(root节点),如果洞穴i在洞穴j的前面,
	则必须先进攻洞穴i方可进攻洞穴j,同时如果一个洞穴有0个bug还必须要舰队进过才可获取brain,其中舰队不走回头路
	一个舰队可以杀死20个bug

	显然思路是 01树形dp,抽象后物品(c,v)为洞穴(bus/20,brain),消耗上限为舰队个数,
	坑啊!!如果存在分叉后消耗为两个0,则消耗必须为2才能全部获取,否则最多获取一个物品,我们在循环的时候控制一下就好了


*/


#pragma comment(linker, "/stack:64000000")
#define _CRT_SECURE_NO_DEPRECATE

#include <queue>
#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
using namespace std;
#define CLR(c,v) memset(c,v,sizeof(c))

template <typename _T>
_T Max(_T a , _T b){
	return (a>b)?(a):(b);
}
template <typename _T>
_T Max(_T a , _T b, _T c){
	return (a>Max(b,c))?(a):(Max(b,c));
}
template <typename _T>
_T Min(_T a , _T b){
	return (a<b)?(a):(b);
}
template <typename _T>
_T Min(_T a , _T b, _T c){
	return (a<Min(b,c))?(a):(Min(b,c));
}

const int inf    = -(1<<30);
const int INF    =  (1<<30);
const int M      =  1e2 +10;
const double eps =  1e-8;

vector <int > p[M];
int v[M];
int c[M];
int dp[M][M];
int n_cavern, max_cost;

void dfs(int cur){
	int len  = p[cur].size();
	for (int i = 0 ; i < len ; i ++){
		int father = cur; 
		int child = p[cur][i];
		dfs(child);
		for (int i = max_cost; i >= c[father]; i--){ //fu ==0 er == 1  fu ==1 
			for(int j=1; j+i<=max_cost ; j++){ // dp[father][i] + dp[child][j] 
				dp[father][i+j] = Max(dp[father][i+j], dp[father][i] + dp[child][j]);
			}
		} 

		// 这个不能保证每一个支路有一个士兵存在,
		//可能所有点的消费为0 一个士兵就全部占领了,这是不对的。(无法控制消费为0的边界)
		//int bound1 = c[father]; 
		//for (int all_cost = max_cost; all_cost >= bound1  ; all_cost--){ // 更新父节点(总消费)
		//	int bound2 = all_cost-c[father];
		//	for(int k = c[father] ; k <= bound2 ; k++){ // 遍历父节点(k)与子节点(all-k)不同消费组合的价值
		//		int child_cost = all_cost - k; // 
		//		dp[father][all_cost] = Max(dp[father][all_cost] , dp[father][k] + dp[child][child_cost] );
		//	}
		//}
	}


}


int main(){
	freopen("in.txt","r",stdin);
	while(cin >> n_cavern >> max_cost , n_cavern!=-1&&max_cost!=-1){
		CLR(dp,0);
		for(int i = 1 ; i <= n_cavern ; i ++)
		{
			cin >> c[i] >> v[i];
			c[i] = (int)ceil(c[i]/20.0-eps);
			p[i].clear();
			for(int j = c[i] ; j <= max_cost ; j++)
				dp[i][j] = v[i]; 
		}
		for(int i = 0 ; i < n_cavern-1 ; i ++)
		{
			int a,b;
			cin >> a >> b;
			if(a>b)	a^=b^=a^=b;
			p[a].push_back(b); // a<b 没有环可以不用标记
		}
		if(max_cost == 0){cout << 0 << endl;continue;}
		dfs(1);	
		cout << dp[1][max_cost] << endl;
	}
	return 0;
}



/*
5 2
0 1 0 1 0 5 0 1 0 2 
1 2 1 3 2 4 2 5 

6 3
0 0 20 10 20 10 20 10 20 0 20 5 
1 2 1 3 1 4 1 5 2 6 

1 0
10 10

5 10
50 10 40 10 40 20 65 30 70 30 
1 2 1 3 2 4 2 5 

7 10
50 10 40 10 40 20 65 30 70 30 35 40 45 20 
1 2 1 3 2 4 2 5 7 3 6 3 

1 1
20 7

5 0
50 10 40 10 40 20 65 30 70 30 1 2 
1 3 2 4 2 5 

4 1
0 10 0 10 0 10 0 10 
1 2 2 3 1 4 

-1 -1


result
9
30
0
50
90
7
0
30

*/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值