HDU1561 The more, The Better

根据题意可以建立一颗树

要想攻占子节点,必须先攻占父亲节点,以这个关系建立森林

在从0号节点引一个关系到所有树根,森林就成为一棵树了

状态定义

opt[i][j]表示以i号节点为根的子树中选择j个点获得的最大价值

状态转移

Gem[i]即输入的b

opt[i][j]=opt[son1][j1]+opt[son2][j2]+....+opt[son-m][jm]+Gem[i]

令d[ii]表示在i号节点的所有子树中选取ii个节点所获得的最大值,通过分组背包计算d数组

则opt[i][j]=d[j-1]+Gem[i]

所以对于opt[i][0...m]可通过求一次分组背包获得的d数组计算得出

代码如下:

#include<cstdio>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
int n,m;
bool flag[220];
int Gem[220];//Gem[i]表示i城堡的宝物数量
vector<int>a[220];//树的存储,城堡的有效编号为1,2,,,n,增加一个不存在0号城堡作为根
int opt[220][220];//opt[i][j]表示i为根的子树中选j个节点获得的最大价值
void dfs(int r)//在以r为根的子树中,计算opt[r][0....m]
{
	flag[r]=true;
	for(int i=0;i<a[r].size();i++)
	{
		if(!flag[a[r][i]])
		{
			dfs(a[r][i]);
		}
	}
	//opt[r][c]=d[c-1]+Gem[i]
	//d[i]表示在r的所有子树中选择i个节点获得的最大值
	int d[220];
	memset(d,0,sizeof(d));
	for(int i=0;i<a[r].size();i++)
	{
		for(int j=m;j>=0;j--)
		{
			for(int k=0;k<=j;k++)
			{
				d[j]=max(d[j],d[j-k]+opt[a[r][i]][k]);
			}
		}
	}
	opt[r][0]=0;
	for(int i=1;i<=m;i++)
	{
		opt[r][i]=d[i-1]+Gem[r];
	}
}
int main()
{
	while(scanf("%d%d",&n,&m),n||m)
	{
		memset(flag,false,sizeof(flag));
		for(int i=0;i<=n;i++)
		{
			a[i].clear();
		}
		for(int i=1;i<=n;i++)
		{
			int A;
			scanf("%d%d",&A,&Gem[i]);
			a[A].push_back(i);
		}
		Gem[0]=0;
		//建树完毕
		m++;
		dfs(0);
		printf("%d\n",opt[0][m]);
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值