Vijos1523 NOI2002 贪吃的九头龙 树形dp
思路不算很难,但细节处理很麻烦
前面建图、多叉转二叉,以及确定dp处理序列的过程都是套路,dp的状态转移过程以注释的形式阐述
#include <cstdio> #include <cstring> #include <algorithm> #include <queue> int N,M,K; struct Edge { int to,next; int weight; void assign(int t,int n,int w) { to=t; next=n; weight=w; } }; Edge elist[]; ]; ]; ][]; //0 is left and 1 is right ]; int ecnt; void initE() { memset(head,-,sizeof(head)); memset(vis,,sizeof(vis)); memset(child,-,sizeof(child)); weight[]=; ecnt=; } inline void addEdge(int from,int to,int weight) { elist[ecnt].assign(to,head[from],weight); head[from]=ecnt++; elist[ecnt].assign(from,head[to],weight); head[to]=ecnt++; } bool input() { scanf("%d%d%d",&N,&M,&K); bool ok=true; >N) ok=false; //输出-1的情况 initE(); int a,b,c; ;i<N;i++) { scanf("%d%d%d",&a,&b,&c); addEdge(a,b,c); } return ok; } void buildBinaryTree(int cur) { vis[cur]=true; ; ;e=elist[e].next) { int& to=elist[e].to; int& w=elist[e].weight; if(!vis[to]) { weight[to]=w; ) child[cur][]=to; else child[last][]=to; last=to; buildBinaryTree(to); } } } ][][]; /* dp[n][m][k]:处理到第n个节点时,大头已经吃掉了m个果子,其父节点将被(k=1)或不被(k=0)大头吃,此情况下的最优值 dp[n]的处理范围:孩子兄弟二叉树中,以节点n为根的子树 dp的初值见下方代码,ans=dp[v][K-1][1],v为孩子兄弟二叉树中1号节点的左孩子 */ std::queue<int> seq; void getSeq(int cur) { ]!=-) getSeq(child[cur][]); ]!=-) getSeq(child[cur][]); seq.push(cur); } //先处理右孩子,再处理左孩子,最后处理自身 /* M>=3时,小头的总难受值的最小值必为0 取两个小头A和B,奇数层的果子由A吃,偶数层的果子由B吃,这样难受值必为0 所以只需考虑大头的难受值 */ int solve_aux_3() //若无特殊说明:solve_aux函数注释中提到的有关树的概念均指孩子兄弟二叉树,opt代指当前决策的较优值,“不吃”和“吃”均指大头 { int ans; while(!seq.empty()) { int cur=seq.front(); seq.pop(); ); ]!=-) st|=; ]!=-) st|=; ) //cur是叶子节点 { dp[cur][][]=dp[cur][][]=; dp[cur][][]=; dp[cur][][]=weight[cur]; } ) //只有右孩子,状态转移和线性dp类似 { ]; dp[cur][][]=; ;i<K;i++) dp[cur][i][]=std::min(dp[rc][i][],dp[rc][i-][]); //对于当前果子,opt=min(不吃,吃) dp[cur][][]=; ;i<K;i++) dp[cur][i][]=std::min(dp[rc][i][],dp[rc][i-][]+weight[cur]); //opt=min(不吃,吃) } ) //只有左孩子 { ]; ) ans=dp[lc][K-][]; //最终答案 else { dp[cur][][]=dp[cur][][]=; ;i<K;i++) dp[cur][i][]=std::min(dp[lc][i][],dp[lc][i-][]); //opt=min(不吃,吃) ;i<K;i++) dp[cur][i][]=std::min(dp[lc][i][],dp[lc][i-][]+weight[cur]); //opt=min(不吃,吃) } } else //st=3,既有左孩子又有右孩子,最复杂的情况 { ]; ]; dp[cur][][]=dp[cur][][]=; ;i<K;i++) //dp[cur][i][0] { ;j<=i;j++) //不吃当前的果子 dp[cur][i][]=std::min(dp[lc][j][]+dp[rc][i-j][],dp[cur][i][]); //分配i,取最优的分配方案 ;j<i;j++) //吃当前的果子 dp[cur][i][]=std::min(dp[lc][j][]+dp[rc][i-j-][],dp[cur][i][]); } ;i<K;i++) //dp[cur][i][1] { ;j<=i;j++) //不吃 dp[cur][i][]=std::min(dp[cur][i][],dp[lc][j][]+dp[rc][i-j][]); ;j<i;j++) //吃 dp[cur][i][]=std::min(dp[cur][i][],dp[lc][j][]+dp[rc][i-j-][]+weight[cur]); } } } return ans; } /* M=2时的dp方程与M>2时形式类似,但细节上有所不同(包括初值的设置和状态转移) 此时大头和小头的难受值必须同时考虑 */ int solve_aux_2() { int ans; while(!seq.empty()) { int cur=seq.front(); seq.pop(); ); ]!=-) st|=; ]!=-) st|=; ) { dp[cur][][]=dp[cur][][]=; dp[cur][][]=dp[cur][][]=weight[cur]; //注意这里赋初值的差异 //dp[cur][0][0]表示原树中当前节点和父节点的果子都由小头吃,所以该段树枝的难受值也必须考虑 //类似的差异会在下方用“!”标注,请读者自行体会 } ) { ]; dp[cur][][]=dp[rc][][]; dp[cur][][]=dp[rc][][]+weight[cur]; //! ;i<K;i++) { dp[cur][i][]=std::min(dp[rc][i][]+weight[cur],dp[rc][i-][]); //! dp[cur][i][]=std::min(dp[rc][i][],dp[rc][i-][]+weight[cur]); } } ) { ]; ) ans=dp[lc][K-][]; else { dp[cur][][]=dp[lc][][]; //! dp[cur][][]=dp[lc][][]+weight[cur]; ;i<K;i++) { dp[cur][i][]=std::min(dp[lc][i][]+weight[cur],dp[lc][i-][]); //! dp[cur][i][]=std::min(dp[lc][i][],dp[lc][i-][]+weight[cur]); } } } else { ]; ]; dp[cur][][]=dp[lc][][]+dp[rc][][]; //! dp[cur][][]=dp[lc][][]+dp[rc][][]+weight[cur]; ;i<K;i++) { ;j<=i;j++) dp[cur][i][]=std::min(dp[cur][i][],dp[lc][j][]+dp[rc][i-j][]+weight[cur]); //! ;j<i;j++) dp[cur][i][]=std::min(dp[cur][i][],dp[lc][j][]+dp[rc][i-j-][]); ;j<=i;j++) dp[cur][i][]=std::min(dp[cur][i][],dp[lc][j][]+dp[rc][i-j][]); ;j<i;j++) dp[cur][i][]=std::min(dp[cur][i][],dp[lc][j][]+dp[rc][i-j-][]+weight[cur]); } } } return ans; } int solve() { memset(dp,0x3f,sizeof(dp)); buildBinaryTree(); getSeq(); ?solve_aux_2():solve_aux_3(); } int main() { if(!input()) printf("-1"); else printf("%d",solve()); ; }
Vijos1523 NOI2002 贪吃的九头龙 树形dp的更多相关文章
- [NOI2002]贪吃的九头龙(树形dp)
[NOI2002]贪吃的九头龙 题目背景 传说中的九头龙是一种特别贪吃的动物.虽然名字叫"九头龙",但这只是 说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的 ...
- [codevs1746][NOI2002]贪吃的九头龙
[codevs1746][NOI2002]贪吃的九头龙 试题描述 传说中的九头龙是一种特别贪吃的动物.虽然名字叫"九头龙",但这只是说它出生的时候有九个头,而在成长的过程中,它有时 ...
- vojis1523 NOI2002 贪吃的九头龙
描述 传说中的九头龙是一种特别贪吃的动物.虽然名字叫“九头龙”,但这只是说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的总数会远大于九,当然也会有旧头因衰老而自己脱落. 有一天, ...
- [NOI2002] 贪吃的九头龙
题目类型:树形DP 传送门:>Here< 题意:有一只九头龙要吃了一颗树,给出一棵\(N\)个节点的带边权的树.九头龙有\(M\)个头,其中一个是大头,大头要吃恰好\(K\)个节点,其他头 ...
- 洛谷 P4362 [NOI2002]贪吃的九头龙
https://www.luogu.org/problemnew/show/P4362 首先有个很显然的dp:ans[i][j][k]表示i节点用j号头,i节点为根的子树中共有k个点用大头时i节点为根 ...
- Vijos1523贪吃的九头龙【树形DP】
贪吃的九头龙 传说中的九头龙是一种特别贪吃的动物.虽然名字叫"九头龙",但这只是说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的总数会远大于九,当然也会有旧头 ...
- Vijos 1523 贪吃的九头龙 【树形DP】
贪吃的九头龙 背景 安徽省芜湖市第二十七中学测试题 NOI 2002 贪吃的九头龙(dragon) Description:OfficialData:OfficialProgram:Converted ...
- 贪吃的九头龙(tyvj P1523)
T2 .tyvj P1523贪吃的九头龙 描述 传说中的九头龙是一种特别贪吃的动物.虽然名字叫“九头龙”,但这只是说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的总数会远大于 ...
- codevs1746 贪吃的九头龙
[问题描述]传说中的九头龙是一种特别贪吃的动物.虽然名字叫“九头龙”,但这只是说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的总数会远大于九,当然也会有旧头因衰老而自己脱落.有一 ...
随机推荐
- 【转】VMware 11安装Mac OS X 10.10 及安装Mac Vmware Tools.
原文网址:http://www.cnblogs.com/Anand/p/4483727.html 先上一张效果图兴奋一下,博主穷屌丝一个,只能通过虚拟黑苹果体验下高富帅的生活,感觉超爽的,废话不多说的 ...
- iso学习网站记录
[零基础学习iOS开发] http://www.cnblogs.com/mjios/archive/2013/04/24/3039357.html 非零基础学习iOS开发2-Objective-C h ...
- 使用sqlhelper的简单增删改查
一:所说的简单的三层构架,就是说没有业务逻辑层,将各层没有放到单独的项目中,解决方案如下: 二:form1.cs的详细代码 using System; using System.Collections ...
- java生成随机整数
1. 使用Random类的nextInt方法: Random rand = new Random(); rand.nextInt(max);, 此时输出[0,max),注意右边是开区间,如果需要设定最 ...
- HDU-1225 Football Score
http://acm.hdu.edu.cn/showproblem.php?pid=1225 一道超级简单的题,就因为我忘记写return,就wa好久,拜托我自己细心一点. 学习的地方:不过怎么查找字 ...
- Eclipse添加快速查找Dao中方法所对应的Mybatis XML映射SQL的插件
Dao关联Mybatis快速查找的插件安装地址:http://dl.bintray.com/harawata/eclipse 安装步骤: ①Eclipse ==> Help ==> Ins ...
- 关于cocos2d和cocos2dx,还有iOS上的cocos2d的ARC问题
好吧,我承认这个我花了N个小时所做的努力都白费了. 事情的开始是这样的,今天在写cocos2dx的时候,测试发现总是出现溢出的问题,总是在main.m的autorelease报错.(好吧,如果我以后发 ...
- Conversion between json and object
public static string ObjToJson<T>(T obj) { DataContractJsonSerializer serializer = new DataCon ...
- Linux的定时任务
分两种:一次性的定时任务.周期性的定时任务. 一次性的定时任务,又称at定时任务,命令为atd ,这里d是deamon的首字母,守护的意思,指守护进程:其实很多程序都是以d结尾,如httpd.memc ...
- 一个很cool的C#的高性能数学库
High Performance Math Library for C# and .NET是一个很cool的C#的高性能数学库,3D效果也很不错,下图是首页上的一个例子.他也有一个交互的网页,你可以自 ...