HDU 1561 The more, The Better

Problem Description

ACboy很喜欢玩一种战略游戏,在一个地图上,有N座城堡,每座城堡都有一定的宝物,在每次游戏中ACboy允许攻克M个城堡并获得里面的宝物。但由于地理位置原因,有些城堡不能直接攻克,要攻克这些城堡必须先攻克其他某一个特定的城堡。你能帮ACboy算出要获得尽量多的宝物应该攻克哪M个城堡吗?

 

 

Input

每个测试实例首先包括2个整数,N,M.(1 <= M <= N <=200);在接下来的N行里,每行包括2个整数,a,b. 在第 i 行,a 代表要攻克第 i 个城堡必须先攻克第 a 个城堡,如果 a = 0 则代表可以直接攻克第 i 个城堡。b 代表第 i 个城堡的宝物数量, b >= 0。当N = 0, M = 0输入结束。

 

 

Output

对于每个测试实例,输出一个整数,代表ACboy攻克M个城堡所获得的最多宝物的数量。

 

 

Sample Input

3 2

0 1

0 2

0 3

7 4

2 2

0 1

0 4

2 1

7 1

7 6

2 2

0 0

 

 

Sample Output

5

13

 

中文题没啥好解释的了。

方法:树形DP+背包。其实就是一个在树上完成的背包问题。f[x][i]表示攻打i个城堡,第i个城堡是x。F[j]就表示攻打j个城堡所获得的宝物数量。F[j] =max(F[j],F[j-k]+f[num[x][i]][[k]]).不做过多赘述了。上代码。

 

 

#include<cstdio>
#include<cstring>
#include<vector>
#include<iostream>
#define S 210
using namespace std;

int f[S][S];
int n ,m;
int tre[S] ,flag[S] ,F[S];
vector<int> num[S];

void deal(int x)
{
	int i ,j ,k;
	flag[x] = 1;

	for(i = 0;i < num[x].size();i++)
	{
		if(flag[num[x][i]]==0)
		{
			deal(num[x][i]);
		}
	}

	memset(F,0,sizeof(F));
	for(i = 0;i < num[x].size();i++)
	{
		for(j = m;j>=0;j--)
		{
			for(k = 0;k<=j;k++)
			{
				if(F[j] < F[j-k] + f[num[x][i]][k])
				{
					F[j] = F[j-k] + f[num[x][i]][k];
				}
			}
		}
	}

	for(i = 1;i <= m;i++)
	{
		f[x][i] = F[i-1] + tre[x];
	}
};

int main()
{
	int i ,j;
	int a ,b;
	while(scanf("%d%d",&n,&m),m+n!=0)
	{
		for(i = 0;i<=n;i++)
		{
			num[i].clear();
		}

		for(i = 1;i<=n;i++)
		{
			scanf("%d%d",&a,&b);
			tre[i] = b;
			num[a].push_back(i);
		}
		tre[0] = 0;

		m++;
		memset(flag,0,sizeof(flag));
		deal(0);
		printf("%d\n",f[0][m]);
	}
	return 0;
}


 

你可能感兴趣的:(HDU 1561 The more, The Better)