树形DP(3) Hdu3593 The most powerful force (泛化背包)

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

The most powerful force

Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 938    Accepted Submission(s): 238


Problem Description
The leaders of AC country made a decision to regain the TW Island. But they have to face the powerful force from USB. So the leaders have to hire some excellent soldiers from the training base called ALPC to format the most powerful force.
The followings are the consists of ALPC:
1.  There are more than one alpcs who are generals, like alpc04.
2.  Every alpc has a direct superior, except the generals.
3.  The alpc who has underling is an officer (Every officer’ number is no more than 500, like alpc21, alpc32).
4.  If send one alpc to the war, so will his direct superior. Of course the general’s direct superior is himself.
5.  Every alpc has two values. Vi is the fighting strength and Ci is the cost that the leader have to pay for the soldier.

Due to the AC country has limited financial resources, the leaders want to format the most powerful force with the cost not exceed G. Obviously, it is an uphill task! Therefore, the leaders of the AC country have assigned the task to alpc72 because of the outstanding behavior he had done at the ACM/ICPC. But alpc72 has been lost in hunting PLMM nowadays, so that he has no time to deal with this problem. What’s more, he left it to you.
 


Input
There will have several test cases.  
The first line has two integers N and G, which stand for the total number of soldiers and the maximum cost. Soldiers numbered consequently from 1 to N. (1<=N<=100000, 1<=G<=10000)
The next N lines, each has three integers Ci, Vi and Fi. They are the cost, the measure of power and the direct superior of the ith soldier. (0<=Ci<=1000000, 0<=Vi<=1000000)
 


Output
Output one integer (must within 32 bits)as the maximum fighting strength of the most powerful force.
 


Sample Input
  
  
5 10 1 2 1 10 5 2 1 1 1 1 1 1 1 1 3 5 10 1 2 1 2 4 2 1 1 1 1 1 1 1 1 3
 


Sample Output
  
  
5 9
Hint
Special Thanks to alpc30.
 


题意:为了得到最强大的战力,现有G的金钱,N个士兵,每个士兵有一个 cost值 和 战斗力值,询问最多能得到多大的战力。

限制条件:士兵之间有上下属关系,每个士兵只有一个直接上司(或自己),可以没有下属,同时,若取了某个士兵,则他的上司也必须参加。

分析:1>.整个军队关系图 是一个森林,因此加一个0号结点做 每颗子树的父亲,则森林变成了树。

2> 对于下属和上司必须同时选取的 限制条件,限制了取的情况:只取上司,取上司和一个下属,取上司和一个下属和下属的下属。。。而这些情况都是互斥的,即在根节点的子树里,只能有一种选取方案,而分配给子树的金钱不同,就可以得到不同的战力值,于是 就可以将每个非叶子节点看做泛化背包(可参见背包九讲-6,7,8讲),将叶子结点当做01背包来做。由根节点 沿树递归搜到叶子节点,做完叶子节点的更新,再由叶子更新父亲结点,就可以更新到0号结点。具体可以看代码注释。

代码:

#include<cstdio>
#include<algorithm>
#define MAX 100005
using namespace std;
bool leaf[MAX];
int dp[505][10005];//非叶子节点最多500个
int G;
int cost[MAX],val[MAX];
struct node{
	int to,nxt;
}edg[MAX];
int head[MAX];
int ind=0;
void dfs(int now,int lim)
{
	int v;
	for (int i = head[now]; i != -1; i = edg[i].nxt)
	{
		v = edg[i].to;
		if(leaf[v])	{//叶子节点
			for (int j = lim; j >= cost[v]; j--)
			{//对叶子结点做01背包,更新父节点
				dp[now][j] = max(dp[now][j-cost[v]]+val[v],dp[now][j]);
			}
		}else{//非叶子节点
			if(lim >= cost[v]){
				for (int j = lim-cost[v]; j >=0 ; j--)
				{//强制将子节点v放入父节点的泛化背包中,因为若想取子节点v的子节点,题目要求要先取v才行,这样才能更新子节点的值。
					dp[v][j] = dp[now][j]+val[v];
				}
				dfs(v,lim-cost[v]);//对儿子节点做背包。
				for (int k = cost[v]; k <= lim; k++)//合并,更新父亲结点
					dp[now][k] = max(dp[v][k-cost[v]],dp[now][k]);
			}
		}
	}
}
void addedge(int u,int v)
{
	edg[ind].to = v;
	edg[ind].nxt = head[u];
	head[u] = ind++;
}
int main()
{
	int n;
	while(~scanf("%d %d",&n,&G))
	{
		ind=0;
		memset(dp[0],0,sizeof(dp));//把零号节点初始化为0。
		memset(head,-1,sizeof(head));
		memset(leaf,1,sizeof(leaf));
		cost[0] = 0;
		int fi;
		for (int i = 1; i <= n; i++)
		{
			scanf("%d %d %d",&cost[i],&val[i],&fi);
			if(fi == i)		fi = 0;			//加上0号节点,原图就由森林变成了树,便于处理。
			addedge(fi,i);
			leaf[fi] = 0;
		}	
		dfs(0,G);	//从根节点开始递归。	
		printf("%d\n",dp[0][G]);
	}
	return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值