您的位置:首页 > 其它

2013寒假练习 1018:没有上司的聚会

2013-02-06 17:20 337 查看
地址:http://acm.bit.edu.cn/mod/programming/view.php?a=504

树形DP好题。终于独立做出一道题。。

题意:给出一棵树的节点的权值,取一个节点集满足没有节点有父子关系,求这个节点集总权值的最大值。

由于当前节点是否取影响其父亲的DP取值,故DP时要分取和不取两种情况。状态转移方程还是比较好想的,可以参见代码。

然后就是具体处理,我是用父亲表示法存树(parent),初始先将所有叶子节点入队,然后依次更新它们的父亲的DP值;用辅助数组child找出他们的父亲并入队。。一直到树根,输出树根的两个DP值中最大的那个。

#include<iostream>
#include<queue>
using namespace std;
#define SIZE 100005
int child[SIZE];   //未被处理的孩子个数
int parent[SIZE];  //记录父亲
int dp[2][SIZE];   //dp[0][]表示不选该节点时子树的最大价值。dp[1][]表示选
int a[SIZE];
int main()
{
int n,i,now,t1,t2;
while(~scanf("%d",&n))
{
memset(child,0,sizeof(child));
memset(dp,0,sizeof(dp));
for(i=1;i<=n;i++)  scanf("%d",&a[i]);
for(i=1;i<=n-1;i++)
{
scanf("%d%d",&t1,&t2);
parent[t1]=t2,child[t2]++;
}
queue<int>q;
for(i=1;i<=n;i++)
{
if(!child[i])         //找到初始处于最底层的(没有孩子),初始化边界条件并入队
{
dp[0][i]=0,dp[1][i]=a[i];
q.push(i);
}
}
for(i=1;i<n;i++)       //对当前已得到DP值的该层节点,以之更新上一层的值
{
now=q.front();
dp[0][parent[now]]+=dp[0][now]>dp[1][now]?dp[0][now]:dp[1][now];          //状态转移方程。不取根就可以取或不取孩子,取了根只能不取孩子
dp[1][parent[now]]+=dp[0][now];
child[parent[now]]--;
if(child[parent[now]]==0)             //若上一层某节点孩子全部处理完毕,则入队
{
q.push(parent[now]);
dp[1][parent[now]]+=a[parent[now]];       //dp[1][]因为取了树根最后还要加上树根的值
}
q.pop();
}
printf("%d\n",dp[0][q.front()]>dp[1][q.front()]?dp[0][q.front()]:dp[1][q.front()]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: