[树形DP入门]没有上司的舞会
2017-09-17 17:29
274 查看
4000
嗯博主作为一个蒟蒻半年忘了验证手机然后……就登不上号了QAQ
趁大休回去博主验证完了可算是能登录了orz
真相:督促博主重新写博客的真正原因是博主找不到放松心情的方法了(最近博主不敢颓废)
各单位注意,前方博主口胡高能预警
树形DP,比线性DP稍微难搞一些,但事实上非常好理解。树拥有一堆能拿出来DP的优秀性质,比如子结构啊(子树)之类的,非常适合出DP题啊(无雾)
既然本来树上的每个节点都有子结构了,那就可以通过两种方式DP
1、从父亲节点推向儿子节点(根–>叶)
2、从儿子节点推向父亲节点(叶–>根)
怎么推呢?当然是利用递归啦,可以从根推向叶子,然后叶子还可以回溯更新根节点数据
当然根据具体的题得抉择一下是弄双向边还是单向边,如果只从叶节点上的数据更新向根节点就能解决问题,省空间的单向边就可以啦~
根据题目要求,可能需要将多叉树转成二叉树再DP,这个得需要注意一下。
那接下来来一道题好了 Luogu P1352
这道题的要求是如果一个节点的父节点被选中,则它不能被选,那么很容易就能推出来递推的式子(至少博主这个DP白痴级的都能推出来),大概就是下面这种情况(r[x]表示该节点被选中时可获得的权值, t[x]表示x被选的情况下其子树最大总和,f[x]则表示x不被选的情况下其子树最大总和,son[x][i]表示x的第i个儿子节点,num[x.son]表示x的儿子节点个数,子树包括自身):
那么我们就只需要从根节点一路搜索到叶节点再更新数据就好了,建树的时候甚至只用建单向边(输入时已经说明了谁是谁的上司,通过入度还能找个根);需要注意输入有可能有负数,用快读的要小心一些。代码如下(码丑勿喷):
总之这是树形DP的一道入门级题目,树形DP更难的题目还多的是,所以想在比赛里碰到树形DP不一脸懵逼还是需要多刷些题的(但容易刷吐= =)。
嗯博主作为一个蒟蒻半年忘了验证手机然后……就登不上号了QAQ
趁大休回去博主验证完了可算是能登录了orz
真相:督促博主重新写博客的真正原因是博主找不到放松心情的方法了(最近博主不敢颓废)
各单位注意,前方博主口胡高能预警
树形DP,比线性DP稍微难搞一些,但事实上非常好理解。树拥有一堆能拿出来DP的优秀性质,比如子结构啊(子树)之类的,非常适合出DP题啊(无雾)
既然本来树上的每个节点都有子结构了,那就可以通过两种方式DP
1、从父亲节点推向儿子节点(根–>叶)
2、从儿子节点推向父亲节点(叶–>根)
怎么推呢?当然是利用递归啦,可以从根推向叶子,然后叶子还可以回溯更新根节点数据
当然根据具体的题得抉择一下是弄双向边还是单向边,如果只从叶节点上的数据更新向根节点就能解决问题,省空间的单向边就可以啦~
根据题目要求,可能需要将多叉树转成二叉树再DP,这个得需要注意一下。
那接下来来一道题好了 Luogu P1352
这道题的要求是如果一个节点的父节点被选中,则它不能被选,那么很容易就能推出来递推的式子(至少博主这个DP白痴级的都能推出来),大概就是下面这种情况(r[x]表示该节点被选中时可获得的权值, t[x]表示x被选的情况下其子树最大总和,f[x]则表示x不被选的情况下其子树最大总和,son[x][i]表示x的第i个儿子节点,num[x.son]表示x的儿子节点个数,子树包括自身):
t[x]=r[x];f[x]=0; for(i=1;i<=num[x.son];i++){ t[x]+=f[son[x][i]]; f[x]+=max(t[son[x][i],f[son[x][i]); }
那么我们就只需要从根节点一路搜索到叶节点再更新数据就好了,建树的时候甚至只用建单向边(输入时已经说明了谁是谁的上司,通过入度还能找个根);需要注意输入有可能有负数,用快读的要小心一些。代码如下(码丑勿喷):
#include<cstdio> using namespace std; const int N=6005; int n,r ,h,t ,f ,rt ; int nxt ,fro ,to ; int getnum(){int num=0,b=1;char c=getchar(); while(c<'0'&&c!='-')c=getchar();if(c=='-')b=-1,c=getchar(); while(c>='0')num=(num<<3)+(num<<1)-'0'+c,c=getchar(); return num*b; } inline void edd(const int &u,const int &v){ nxt[++h]=fro[u],fro[u]=h,to[h]=v;rt[v]++; } inline int max(const int &a,const int &b){ if(a>b)return a;return b; } void src(int now){ t[now]=r[now];f[now]=0; for(int i=fro[now];i;i=nxt[i]){ src(to[i]); t[now]+=f[to[i]]; f[now]+=max(t[to[i]],f[to[i]]); } } int main(){register int i,l,k,root;n=getnum(); for(i=1;i<=n;++i)r[i]=getnum(); for(i=1;i<n;++i){l=getnum(),k=getnum();edd(k,l);} for(i=1;i<=n;++i) if(rt[i]==0){root=i;break;} src(root); return printf("%d\n",max(t[root],f[root])),0; }
总之这是树形DP的一道入门级题目,树形DP更难的题目还多的是,所以想在比赛里碰到树形DP不一脸懵逼还是需要多刷些题的(但容易刷吐= =)。
相关文章推荐
- Codevs 1380 没有上司的舞会 [树形dp]
- tyvj 1052 没有上司的舞会 树形DP
- CodeVS 1380 没有上司的舞会(树形DP)
- [树形DP] 猴腮雷 (没有上司的舞会)
- 【CS 1380】没有上司的舞会(树形dp+dfs)
- 【codevs 1380】没有上司的舞会(树形dp)
- 洛谷p1352没有上司的舞会 树形dp
- 【codevs1380】没有上司的舞会 树形dp经典题目
- code【vs】1380 没有上司的舞会(树形dp)
- 【洛谷 2016】战略游戏 树形dp经典题目(类似没有上司的舞会)
- CODEVS1380 没有上司的舞会 (树形DP)
- 没有上司的舞会 树形DP 经典题目
- 树形DP--codevs 1380 没有上司的舞会
- 【codevs1380】没有上司的舞会 树形dp
- CodeVS.1380 没有上司的舞会 (树形DP)
- codevs 1380 没有上司的舞会 树形DP
- 【树形dp】没有上司的舞会
- 洛谷P1352 没有上司的舞会——树形DP
- 没有上司的舞会(树形dp裸题)
- 树形dp——没有上司的舞会