树状DP1

刷DP例题刷到了树状DP…???

想着deadline要到了,就赶紧刷完了深度搜索作业,然后发现有DP例题做了下,石子归并是环形的(我就记得是环形,tsoj怎么不是T_T),然后看到了P1352 没有上司的舞会好歹写个题解 纪念下今天的追赶deadline 就这一题了!

这是一个简单的树状DP

先上题目描述

题目描述
某大学有N个职员,编号为1~N。他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数Ri,但是呢,如果某个职员的直属上司来参加舞会了,那么这个职员就无论如何也不肯来参加舞会了。所以,请你编程计算,邀请哪些职员可以使快乐指数最大,求最大的快乐指数。
输入输出格式
输入格式:

第一行一个整数N。(1<=N<=6000)
接下来N行,第i+1行表示i号职员的快乐指数Ri。(-128<=Ri<=127)
接下来N-1行,每行输入一对整数L,K。表示K是L的直接上司。
最后一行输入0 0
输出格式:

输出最大的快乐指数。

树状DP1_第1张图片

首先考虑存储方式6000的数据,bool都要爆,不可能是邻接
从子节点向上DP
对每一个父节点 我们考虑取不取 如果取 子节点都不能取 因为如果直接保留到该节点最大值,则无法满足无后效性,故增一维,分别记录取和不取的最大值 以及两者中的最大值 分别为a[i][1] a[i][2] a[i][0]

然后我们可以考虑下这题的处理方法 深搜不佳 自根部向上 反向的拓扑排序为一不错选择

也就是入出度存储倒过来

用队列存储入度为0的节点

然后是代码

#include
#include
#include
using namespace std;
int main()
{
 int i,u,v,n,sum;
 int s[6001],r[6001],a[6001][3],f[6001];
 memset(a,0,sizeof(a));
 memset(f,0,sizeof(f));
 memset(r,0,sizeof(r));
 memset(s,0,sizeof(s));
 cin>>n;
 for (i=1;i<=n;i++)
 {
  cin>>r[i];
 }
 for (i=1;i<=n-1;i++)
 {
  cin>>u>>v;
  f[u]=v;
  s[v]++;
 }
 queue q;
 for (i=1;i<=n;i++)
  if (s[i]==0) q.push(i);
 while (!q.empty())
 {
  v=q.front();
  q.pop();
  if (r[v]+a[v][2]>a[v][1]) a[v][0]=r[v]+a[v][2]; else a[v][0]=a[v][1];
  if (f[v]!=0)
   {
    i=f[v];
    a[i][1]=a[i][1]+a[v][0];
    a[i][2]=a[i][2]+a[v][1];
    a[v][0]=0;
    s[i]--;
    if (s[i]==0) q.push(i);
   }
 }
 sum=0;
 for (i=1;i<=n;i++)
 sum=sum+a[i][0];
 cout<

以上 关机背单词 洗洗睡了
明天又是元气满满(翘掉早操)的一天呢!

你可能感兴趣的:(其他)