您的位置:首页 > 其它

codevs愚蠢的矿工(树形DP)

2016-04-25 19:30 357 查看
/*
树形DP
根节点一定有人 然后 剩下的人没到每个孩子去
因为孩子数可能很多 不好枚举 所以转二叉树 分两部分 O(sum)就可以了
当然 转二叉树候必须顾及原来树的一些性质 如不能只选左孩子
转化好了之后就是DP了
写的记忆化 递归每个节点 枚举分给左右孩子的人数
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 1010
using namespace std;
int n,m,son[maxn][3];
int f[maxn][maxn],a[maxn],ans;
int DP(int k,int sum)//到节点k时 还剩sum个人没有用
{
int i,maxx=0;
if(f[k][sum]!=0)return f[k][sum];//记忆化
if(k==0||sum==0)return 0;//剪枝
f[k][sum]=a[k];//先整一个人在k处
for(i=1;i<=sum;i++)//枚举给左孩子多少人 i-1
{
if(DP(son[k][2],i-1)+a[k]+DP(son[k][1],sum-i)>maxx)
maxx=DP(son[k][2],i-1)+a[k]+DP(son[k][1],sum-i);
if(DP(son[k][2],i)>maxx)maxx=DP(son[k][2],sum);//特殊情况 不要k 只要右孩子
//因为这是多叉树转化来的 所以可以实现相反的 不能只要左孩子 因为左孩子和k连在一起
}
if(f[k][sum]<maxx)
f[k][sum]=maxx;
return f[k][sum];
}
int main()
{
cin>>n>>m;
int i,x,y;
for(i=1;i<=n;i++)cin>>a[i];
for(i=1;i<=n;i++)
{
cin>>x>>y;
if(son[x][1]==0)son[x][1]=y;
else
{
int fa=son[x][1];
while(son[fa][2])fa=son[fa][2];
son[fa][2]=y;
}
}
ans=DP(son[0][1],m);
cout<<ans;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: