https://www.luogu.com.cn/problem/P1352

题目描述

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

输入格式

第一行一个整数N。(1<=N<=6000)

接下来N行,第i+1行表示i号职员的快乐指数Ri。(-128<=Ri<=127)

接下来N-1行,每行输入一对整数L,K。表示K是L的直接上司。

最后一行输入0 0

输出格式

输出最大的快乐指数。

输入输出样例

输入 #1复制

7
1
1
1
1
1
1
1
1 3
2 3
6 4
7 4
4 5
3 5
0 0
输出 #1复制

5样例分析:

根节点为5,那么3,4不去,就可以获得最大快乐值=5

思路:可用树形DP或者拓扑排序来做一开始想到的可能是用一个一维数组dp[i]表示在第i个人的位置能获得的最大快乐,但是这个位置上的人去或者不去,都会对下属有影响,具有后效性,
比如说dp[2]作为根节点,那么他的最优解肯定是这个节点的快乐值,如果3要参加,则dp[3]无法继承dp[2]的最优解

那么我们可以在这个基础上增加一维,用来1/0表示这个人去还是不去如果不去,那么他的直接下属都可以去,dp[i][0]=sum((max(dp[son][1],dp[son][0])) son表示员工若去,则他的直接下属都不能去,dp[i][1]=sum(dp[son][0]);
 

那什么是后效性?

无后效性,有两层含义。

第一层含义是,在推导后面阶段状态的时候,我们只关心前面阶段的状态值,不关心这个状态是怎么一步步推导出来的。

第二层含义是,某阶段状态一旦确定,就不受之后阶段的决策影响。无后效性是一个非常“宽松”的要求。只要满足前面提到的动态规划问题模型,其实基本上都会满足无后效性。

---来源CSDN博客

简单些的例子:迷宫问题中,假设你走到了(n,m)点,之后的状态转移不会再关心你是如何走到(n,m)点的,只关心你在(n,m)点的状态信息(例如耗费)。

之后发生的不会影响之前的结果。拿最长公共子序列来说,你在后面碰到的字符不会影响你前面字符的匹配数量和结果,每次增加匹配到的字符时,都是“继承”前面的结果之后加一。所以如果后面的字符如果能改变前面的字符,那么我们存状态意义就不大了。就是因为有大量重复计算在递归里,我们才用空间换时间,用了动态规划。如果状态总是变,那也没必要存了。每次都暴力算就行。---来源知乎某处(我忘了)

所以我们需要在这个基础上再加上一维,分别以0和1表示这个人去或者不去。
 #include<iostream>
 #include<cstring>
 #include<math.h>
 #include<stdlib.h>
 #include<cstring>
 #include<cstdio>
 #include<utility>
 #include<algorithm>
 #include<queue>
 using namespace std;
 typedef long long ll;
 inline int read(){
     ,w=;;
     while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
     )+(X<<)+(ch^),ch=getchar();
     return w?-X:X;
 }
 /*------------------------------------------------------------------------*/
 ;
 ],fa[maxn];
 vector<int>son[maxn];
 ;
 void bfs(int root){

     queue<int>q;
     q.push(root);
     vis[root]=;
     tree[++cnt]=root;

     while(!q.empty()){

         int now=q.front();q.pop();

         int len=son[now].size();

         ;i<len;++i){

             if(!vis[son[now][i]]){
                 vis[son[now][i]]=;
                 tree[++cnt]=son[now][i];
                 q.push(son[now][i]);
             }

         }

     }

 }
 int main( )
 {
     ios_base::sync_with_stdio(); cin.tie(); cout.tie();
     //freopen("a.txt","r",stdin);
     //freopen("a.txt","w",stdout);
     int n;
     cin>>n;
     ;i<n+;++i){
         fa[i]=i;
         cin>>v[i];

     }
     ;i<=n;++i){
         int u,v;
         cin>>u>>v;
         )break;

         fa[u]=v;
         son[v].push_back(u);

     }

     int root = n;

     while(fa[root]!=root)root=fa[root];

     bfs(root);

     //从叶子节点开始dp
     ;--i){

         int now=tree[i];
         int len=son[now].size();

         ;j<len;++j){//他的某一个下属 

             //1表示去
             dp[now][]+=max(dp[son[now][j]][],dp[son[now][j]][]);
             dp[now][]+=dp[son[now][j]][]; //如果now去,则now的下属不能去
         }

         dp[now][]+=v[now];
         //根节点,写在外面的原因是
         //叶子节点无法进入第二层循环
         //并且叶子节点表示now去,所以二维状态是1 

     }

     cout<<(max(dp[root][],dp[root][]))<<endl;

     ;
 }
拓扑排序的DP思想和上面的差不多,就是省略了建树的过程,因为拓扑排序的算法特殊性帮助我们完成了这一过程,根节点入度为0,那么我们就可以不断地在排序过程中完成DP
 #include<iostream>
 #include<cstring>
 #include<math.h>
 #include<stdlib.h>
 #include<cstring>
 #include<cstdio>
 #include<utility>
 #include<algorithm>
 #include<queue>
 #include<vector>
 #include<map>
 using namespace std;
 ;
 ];
 int n;

 int main(){

     cin>>n;

     ;i<=n;++i){
         cin>>a[i];
     }
     vector<int>son[maxn];
     int u,v;
     while(cin>>u>>v&&u&&v){

         du[v]++;

         son[u].push_back(v);
     }

     queue<int>q;
     ;i<=n;++i){

         if(!du[i]){//叶子节点
             q.push(i);
             dp[i][]=a[i];
         }
     }
     map<int,int>mp;
     ;
     while(!q.empty()){

         int now=q.front();q.pop();
         int len=son[now].size();

         ;i<len;++i){

             int boss=son[now][i];
             dp[boss][]+=max(dp[now][],dp[now][]);
             dp[boss][]+=dp[now][];

             du[boss]--;
             if(!du[boss]){
                 dp[boss][]+=a[boss];
                 q.push(boss);
                 mp[i]=;
             }
             ans=max(dp[boss][],dp[boss][]);
         }

     }
     cout<<ans<<endl;
     ;
 } 

发现我这个代码写的有点复杂。。。

参考了一位大佬的代码,和我的代码的区别是我用vector存每个节点的上司,那么判断过程中就需要每次从vector里面取出,其实我们只需要设置一个father数组用来存储就可以了

 #include<iostream>
 #include<cstring>
 #include<math.h>
 #include<stdlib.h>
 #include<cstring>
 #include<cstdio>
 #include<utility>
 #include<algorithm>
 #include<queue>
 using namespace std;
 typedef long long ll;
 inline int read(){
     ,w=;;
     while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
     )+(X<<)+(ch^),ch=getchar();
     return w?-X:X;
 }
 /*------------------------------------------------------------------------*/
 ;
 ],father[maxn],du[maxn];
 ;
 int main( )
 {
     ios_base::sync_with_stdio(); cin.tie(); cout.tie();
     //freopen("a.txt","r",stdin);
     //freopen("a.txt","w",stdout);

     int n;
     cin>>n;
     ;i<n+;++i){
         father[i]=i;
         cin>>v[i];

     }
     ;i<=n;++i){
         int u,v;
         cin>>u>>v;
         )break;

         father[u]=v;

         du[v]++;

     }
     queue<int>q;
     ;i<=n;++i){
         if(!du[i]){

             q.push(i);
         }

     }
     int root;
     while(!q.empty()){

         int now=q.front();q.pop();
         root=now;
         //上司不去
         dp[father[now]][]=max(dp[now][],dp[now][]);
         //去
         dp[father[now]][]+=v[father[now]]+dp[now][]; 

         du[father[now]]--;
         if(!du[father[now]]){
             q.push(father[now]);
         }
     }
     cout<<max(dp[root][],dp[root][])<<endl;

     ;
 }

P1352 没有上司的舞会&&树形DP入门的更多相关文章

  1. P1352 没有上司的舞会——树形DP入门

    P1352 没有上司的舞会 题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.现在有个周年庆宴会,宴会每邀请来一个职员 ...

  2. 洛谷P1352 没有上司的舞会——树形DP

    第一次自己写树形DP的题,发个博客纪念`- 题目来源:P1352 没有上司的舞会 题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结 ...

  3. P1352 没有上司的舞会[树形dp]

    题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数Ri, ...

  4. [luogu]P1352 没有上司的舞会[树形DP]

    本Lowbee第一次写树形DP啊,弱...一个变量写错半天没看出来...... 题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点 ...

  5. 洛谷 P1352 没有上司的舞会 树形DP板子

    luogu传送门 题目描述: 某大学有n个职员,编号为1~n. 他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司. 现在有个周年庆宴会,宴会每邀请来一个职员都会 ...

  6. 洛谷 P1352 没有上司的舞会(树形 DP)

    题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数Ri, ...

  7. 『没有上司的舞会 树形DP』

    树形DP入门 有些时候,我们需要在树形结构上进行动态规划来求解最优解. 例如,给定一颗\(N\)个节点的树(通常是无根树,即有\(N-1\)条无向边),我们可以选择任意节点作为根节点从而定义出每一颗子 ...

  8. CodeVS1380 没有上司的舞会 [树形DP]

    题目传送门 没有上司的舞会 题目描述 Description Ural大学有N个职员,编号为1~N.他们有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.每个职员有一个 ...

  9. 没有上司的舞会 树形dp

    题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数Ri, ...

随机推荐

  1. Ext.grid 分页

    1. 定义变量,存储,每页显示多少条数据 var itemsPage = 25; 2.grid数据源 //列表源 var oStore = Ext.create('Ext.data.Store', { ...

  2. SpringCloud学习系列<一>版本介绍

    SpringCloud学习踩坑记<一> SpringCloud版本迭代实在太快,学习起来也是各种坑,博主用的是"当前"的最新版本,借鉴周立老大的Spring Cloud ...

  3. 玩转控件:封装Dev的LabelControl和TextEdit

    俗话说的好:"工欲善其事必先利其器",作为软件攻城狮也是同样道理,攻城狮开发的软件目的是简化客户的操作,让客户动动手指就可以完成很多事情,减少人力成本.这也是系统/软件存在的目的. ...

  4. Android AlertDialog 各种弹框代码

    1.消息框 btn01.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ...

  5. 为什么我推荐你用Ubuntu开发?

    前言: 鱼哥在做多媒体开发时,领导倒逼我们用Ubuntu开发,后来才发现它的牛逼和高效.所以对于还在用Windows上开发的朋友,鱼哥建议,趁周末,搞个双系统,切到Ubuntu上开发, Ubuntu最 ...

  6. Celery框架的基本使用方法

    一. Celery简介 Celery是一个简单.灵活且可靠的,处理大量消息的分布式系统,专注于实时处理的异步任务队列,同时也支持任务调度. Celery的架构由三部分组成,消息中间件(message ...

  7. div 3 frog jump

    There is a frog staying to the left of the string s=s1s2…sn consisting of n characters (to be more p ...

  8. Python IDE ——Anaconda+PyCharm的安装与配置

    一 前言 最近莫名其妙地想学习一下Python,想着利用业余时间学习一下机器学习(或许仅仅是脑子一热吧).借着研究生期间对于PyCharm安装的印象,在自己的电脑上重新又安装了一遍.利用周末的一点时间 ...

  9. Cows POJ - 2481 (树状数组 + 单点更新 + 区间查询)

    Cows 思路:我们可以按照每个范围的S从小到大排序,相同的S按E从大到小排序,这样的好处是当前范围的S一定大于等于之前范围的S(即当前的范围可能被之前范围的包围),那么我们只需要统计之前的范围E比当 ...

  10. H - Bone Collector

    H - Bone Collector Many years ago , in Teddy's hometown there was a man who was called "Bone Co ...