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. java-随机点名器(新手)

    //创建的一个包名. package qige; //导入一个包.import java.util.Random; //定义一个类.public class Zy1 { //公共静态的主方法. pub ...

  2. setTimeout和setImmediate到底谁先执行,本文让你彻底理解Event Loop

    笔者以前面试的时候经常遇到写一堆setTimeout,setImmediate来问哪个先执行.本文主要就是来讲这个问题的,但是不是简单的讲讲哪个先,哪个后.笼统的知道setImmediate比setT ...

  3. [组件封装]微信小程序-日历

    描述 切换月份, 当天文案为今天, 日期背景变色, 日期红点标识, 点击选中日期. 效果 源码 calendar.wxml <view class="component"&g ...

  4. matplotlib 的几种柱状图

    1.x 表示数量,y 表示名字 import matplotlib.pyplot as plt dic = {'a': 22, 'b': 10, 'c': 6, 'd': 4, 'e': 2, 'f' ...

  5. 第七周java实验作业

    实验七 继承附加实验实验时间 2018-10-11 1.实验目的与要求 (1)进一步理解4个成员访问权限修饰符的用途: Public  该类或非该类均可访问 Private  只有该类可以访问 Pro ...

  6. fastText 训练和使用

    2019-09-09 16:33:11 问题描述:fastText是如何进行文本分类的. 问题求解: fastText是一种Facebook AI Research在16年开源的一个文本分类器. 其特 ...

  7. PIGS POJ - 1149网络流(最短增广路---广搜) + 建图

    题意: 第一行输入m和n,m是猪圈的数量,n是顾客的数量,下面n行 第 i+1行表示第i个顾客 , 输入第一个数字表示有几把猪圈的钥匙,后面输入对应的猪圈,最后一个数字输入顾客想买几头猪. 建图: 设 ...

  8. Git使用的一些问题:.gitignore规则不生效、git同步代码至github和gitee

    Git忽略规则及.gitignore规则不生效的解决办法 .gitignore 的基本使用 在git中如果想忽略掉某个文件,不让这个文件提交到版本库中,可以使用修改根目录中 .gitignore 文件 ...

  9. pthread_rwlock_t

    一.读写锁 读写锁实际是一种特殊的自旋锁,它把对共享资源的访问者划分成读者和写者,读者只对共享资源进行读访问,写者则需要对共享资源进行写操作. 读操作可以共享,写操作是排他的,可以有多个在读(与 CP ...

  10. [POJ2533]Longest Ordered Subsequence<dp>

    题目链接:http://poj.org/problem?id=2533 描述: A numeric sequence of ai is ordered if a1 < a2 < ... & ...