[XXSY]树形DP专题 刷题笔记
Mistletoes · · 个人记录
树形DP专题
树的最大独立集
题目:
对于一棵有N个结点的无根树,选出尽量多的结点,使得任何两个结点均不相邻(称为最大独立集)。
题解:
用
如果一个点没选,它的儿子选不选随便;如果一个点选了,它的儿子不能选
周年庆宴 Hdu 1520
题目:
很多领导,能形成一个树形关系网,这些领导参加一个party,每个人都有一个能使party活跃的值,但是每个人又不会跟自己的直接领导同时参加party。为使party气氛最好,求最好气氛值。
题解:
就是求树的最大独立集
二叉苹果树 URAL(GZ六中译)
题目:
有一棵苹果树,该苹果树是一棵二叉树,共N个节点,树节点编号为1~N,编号为1的节点为树根,边可理解为树的分枝,每个分枝都长着若干个苹果,现在要要求减去若干个分支,保留M个分支,要求这M个分支的苹果数量最多。
题解:
先明确不能去父留子。
设
选课
题目:
N 门功课,每门课有个学分,每门课有一门或没有直接先修课(若课程 a 是课程 b 的先修课即只有学完了课程 a,才能学习课程 b)。一个学生要从这些课程里选择 M 门课程学习,问他能获得的最大学分是多少?
题解:
树形背包
将每门课的直接先修课与其相连。易知,课与课间的先修关系构成一片森林。
建一个虚点0,把森林中每棵树的根节点与0号节点相连,这样森林就转成了以0号点为根的树。 DP时把0号节点列入必选的范围,选m+1门课即可
设
注意选择
LazyChild黑OJ
题目:
对于n种木马,有且仅有(n-1)对不能共存,并且对于每种木马,都存在至少一个木马与之不能共存。问最多可获取木马的个数。
题解:
树上最大独立集。
加分二叉树
题目:
设一棵 n 个节点的二叉树 tree 的中序遍历为(1,2,3,…,n), 每个节点都有一个分数(均为正整数),tree 及它的每个子树都有一个加分。
任一棵子树 subtree(也包含 tree 本身)的加分 = subtree 的左子树的加分 × subtree 的右子树的加分 + subtree 的根的分数。
若某个子树为空,规定其加分为 1,叶子的加分就是叶节点本身的分数。不考虑它的空子树。
试求一棵符合中序遍历为 (1,2,3,…,n) 且加分最高的二叉树 tree。要求输出
- tree 的最高加分。
- tree 的前序遍历。
题解:
一种常见的区间dp题,设
具体地,二叉树的加分取决于谁是根,于是我们就在区间内枚举根k。
因为要输出二叉树的前序遍历,所以再开一个
战略游戏
题目:
求树的最小点覆盖数。(点覆盖:点集合使得任意一条边至少有一个端点在集合中)
题解:
用
如果一个点选了,它的儿子选不选无所谓;如果一个点没选,它的所有儿子都要选
黑手党(Poj 3107 Godfather)
题目:
求树的重心。(树的重心满足:在删除它后,包含最多节点的剩余连通块的节点数最小)
题解:
板子。
通向自由的钥匙
题目:
通向自由的钥匙被放n个房间里,这n个房间由n-1条走廊连接。但是每个房间里都有特别的保护魔法,在它的作用下,我无法通过这个房间,也无法取得其中的钥匙。虽然我可以通过消耗能量来破坏房间里的魔法,但是我的能量是有限的。那么,如果我最先站在1号房间(1号房间的保护魔法依然是有效的,也就是,如果不耗费能量,我无法通过1号房间,也无法取得房间中的钥匙),如果我拥有的能量为P,我最多能取得多少钥匙?
题解:
题目可看作简单的树上背包,多叉树转二叉树后,设
多叉树转二叉树的方法——左儿子右兄弟表示法: 在每个点存一个左节点,一个右节点,左节点表示与其同层的兄弟,右节点表示其儿子。
关于多叉树转二叉树
void Pre(int x)//多叉树转二叉树
{
vis[x]=true;
for(int i=1;i<=n;++i)
if(!vis[i]&&graph[x][i])
{
r[i]=l[x];
l[x]=i;
Pre(i);
}
return;
}
void DFS(int x)//dp
{
if(l[x])DFS(l[x]);
if(r[x])DFS(r[x]);
for(int i=0;i<=m;++i)
{
f[x][i]=f[r[x]][i];//注意这一句
for(int j=0;j<=i-cost[x];++j)
f[x][i]=max(f[x][i],key[x]+f[l[x]][j]+f[r[x]][i-j-cost[x]]);
}
}
寻宝之旅
题目:
给一棵树,树上每个点有一定价值的宝藏。 探险队从其中的一点出发,每次他们可以留一个人在此点开釆宝藏,也可以不留,然后其余的人可以分成若干队向这一点相邻的点走去。 需要注意的是,如果他们把队伍分成两队或者两队以上,就必须留一个人在当前点,提供联络和通讯,当然这个人也可以一边开采此地的宝藏。 并且, 为了节约时间,队伍在前往开釆宝藏的过程中是不会走回头路的。 请计算探险队所能开釆的最大宝藏价值。
题解:
变形的树上背包
设
电脑网络 Hdu 2196
题目:
给定一棵树,对于每个点,求该点到与它距离最远的点的距离
题解:
换根dp
很经典的一道可以当板子背的题了
用
第一次dp求出
最后答案即为
偷天换日
题目:
艺术馆由若干个展览厅和若干条走廊组成。每一条走廊的尽头不是通向一个展览厅,就是分为两个走廊。每个展览厅内都有若干幅画,每幅画都有一个价值。经过走廊和偷画都是要耗费时间的。 警察会在n秒后到达进口,在不被逮捕的情况下你最多能得到的价值。
题解:
先把走廊和展览厅抽象成树模型:
每条走廊相当于树上的一个节点,过一个节点的时间代价为
走廊尽头通向展览厅,相当于该走廊代表的树上节点为叶子节点,且此处有
走廊分叉为两条走廊,相当于该走廊代表的树上节点有两个儿子。
问题转成树上01背包。
坑点:
- 小偷在n-1秒时就必须离开
- 走廊必须走一来一回两遍
实现技巧:
因为建的是棵二叉树,所以采用“当前节点为
设
(左儿子花
电视网络(Poj 1155 TELE)
题目:
电视网络计划广播一个重要的足球比赛。他们的网络传输关系可以认为是一棵树。树的根即为广播比赛的电视台,叶子节点表示网络用户,其他节点表示中转站。
从一个节点向另一个节点传输广播的费用是给定的。总的传输费用为所有传输广播的边的费用之和。
每个用户愿意支付一定的报酬来观看足球比赛,电视网络决定是否给其提供广播信号。
写一个程序计算在电视网络不亏本的前提下(即看到比赛的用户的报酬之和-总的传输费用>=0),最多可以让多少人看到足球比赛。
题解:
直接用 “在不亏本的前提下最多可以让多少人看到比赛” 设状态的话,状态很难转移。
所以转换一下:
设
不难看出这是一个树上的分组背包。(背包的总容量相当于该点为根节点的子树中所有的用户数量;组数就是连接的儿子个数;把该节点的每个儿子看成一组,每组中的元素为选一个,选两个...选n个用户。)
附1:多叉树上的背包详解
附2:分组背包:若干组物品,每组中的物品互相冲突(就是说每组中最多只能选一件物品),求最大价值
for(int k=1;k<=总共的组数;k++)//遍历所有的组k
for(int j=v;j>=1;j--)//跟01背包类似,倒序枚举背包容量
for(int i=1;i<=组中的元素个数;i++)//遍历这组中所有的元素
消防站(Poj 2152 Fire)
题目:
Z国有N个城市,编号为1~N。城市之间用高速公路连接,任意两个城市之间有且仅有一条路径。
最近,Z国火灾频发,于是政府决定在一些城市建立一些消防站,在城市K建立消防站需要花费W(K),每个城市的W可能不同。
如果不在城市K建立消防站,那么需要保证离K最近的消防站与K的距离不超过D(K)。每个城市的D可能不同。
为了节省开支,政府希望你计算满足要求的最小花费。
题解:
国家集训队2006论文集 陈启峰 (例题三就是)
河流 IOI(Amber译)
题目: 几乎整个Byteland王国都被森林和河流所覆盖。小点的河汇聚到一起,形成了稍大点的河。就这样,所有的河水都汇聚并流进了一条大河,最后这条大河流进了大海。这条大河的入海口处有一个村庄——名叫Bytetown.
在Byteland国,有n个伐木的村庄,这些村庄都座落在河边。目前在Bytetown,有一个巨大的伐木场,它处理着全国砍下的所有木料。木料被砍下后,顺着河流而被运到Bytetown的伐木场。Byteland的国王决定,为了减少运输木料的费用,再额外地建造k个伐木场。这k个伐木场将被建在其他村庄里。这些伐木场建造后,木料就不用都被送到Bytetown了,它们可以在运输过程中第一个碰到的新伐木场被处理。显然,如果伐木场座落的那个村子就不用再付运送木料的费用了。它们可以直接被本村的伐木场处理。
注:所有的河流都不会分叉,形成一棵树,根结点是bytetown。
国王的大臣计算出了每个村子每年要产多少木料,你的任务是决定在哪些村子建设伐木场能获得最小的运费。其中运费的计算方法为:每一吨木料每千米1分钱。
编一个程序:
1.从文件读入村子的个数,另外要建设的伐木场的数目,每年每个村子产的木料的块数以及河流的描述。
2.计算最小的运费并输出。
题解:
按照一般思路考虑,先设
但因为不知道各节点的木材具体运到多远,运费不好统计。
于是我们再加一个限制条件,设
列状态转移方程,发现还要讨论在
最后决定设四维的状态
转移方程如下:
dp[x][anc][k][0] = Min(dp[x][anc][k][0],dp[v][anc][l][0] + dp[x][anc][k - l][0]);
dp[x][anc][k][1] = Min(dp[x][anc][k][1],dp[v][x][l][0] + dp[x][anc][k - l][1]);
ps.可以开一个动态栈记录祖先
又是DEBUG
题目:
Bugzilla由N个基地组成。这N个基地被N-1段双向地道连接在一起,每段地道都连接两个基地,并且保证任意两个基地之间都可以通过地道互相到达。Bug就藏在其中的某段地道中。
开始时rc可以乘坐运输机降落在任何一个基地。每次到达一个基地时,rc都可以选择呼叫运输机将他和他的部队运输到任意另一个基地,或者进入与这个基地相邻的一段地道进行搜索。但为了防止Bug跑进已经搜索过的地道,他在离开一个基地进入地道或登上运输机时一定会将这个基地炸毁。基地一旦被炸毁就不再和与它相邻的地道连接。但这样一来,如果进入的地道另一端的基地已经在之前被炸毁,rc和他的部下就将被永远困在地道中。因为地道生活并不有趣,所以在这种情况下rc是不会进入这段地道的。
不过,这也带来了一个问题,就是rc也许不能搜索所有的地道了。现在rc想知道的是他最多能搜索多少段地道。
题解:
题意转换:保留若干条链,让删去的边最少
贪心解决:
度=1:该点为链的一段,不用删
度=2:该点为链的中间,不用删
度>2:删去(度-2)条边,且优先删除和父节点连边
证明:设该点为
u ,u 至少有2个儿子,设v1 的子树为所有儿子的子树中最高的,v2 的子树为次高的,那么保留树链“-v1-u-v2- ”一定比保留树链“-fa-u-v1- ”优
void DFS(int x,int fa)
{
vis[x]=1;
for(int i=head[x];i;i=nxt[i])
if(!vis[e[i]]) DFS(e[i],x);
if(du[x]>2)n-=du[x]-2,du[fa]--;//删去连父亲的边,父亲度数-1
return;
}
kingdom
CF613D Kingdom and its Cities
题目:
一个王国有n座城市,城市之间由n-1条道路相连,形成一个树结构,国王决定将一些城市设为重要城市。
这个国家有的时候会遭受外敌入侵,重要城市由于加强了防护,一定不会被占领。而非重要城市一旦被占领,这座城市就不能通行。
国王定了若干选择重要城市的计划,他想知道,对于每个计划,外敌至少要占领多少个非重要城市,才会导致重要城市之间两两不连通。如果外敌无论如何都不可能导致这种局面,输出-1
题解:
先建出虚树,不难发现要删最少的点肯定是挑虚树上的点删。
考虑如何求解题目的问题:
设
方程:
(
注意:
- 我们要获得的子树的根并不一定要是整棵树的根节点,因此我们需要枚举每一个节点为根的小子树,看看哪一个删边数是最小的
- 小子树的根
i 不是整棵树的根节点时,正确删边数是f[i][p]+1 ,因为要删去i 与i 的父亲相连的边
hdu1011
题目:
有n个洞组成一棵树,你有m个士兵,你从1号房间开始攻打,每个洞有a个"bugs"和b的价值。你的一个士兵可以打20个"bugs",为了拿到这个洞的价值b你必须留下k个士兵消灭这个洞的所有"bugs"(k*20>="bugs"的数量,且留下的士兵不可以再去攻打其他的洞,且必须攻打了前面的洞才可以攻打后面的洞)。问你花费这m个士兵可以得到的最大价值是多少。
题解:
树上背包
hdu1561
题目:
ACboy很喜欢玩一种战略游戏,在一个地图上,有N座城堡,每座城堡都有一定的宝物,在每次游戏中ACboy允许攻克M个城堡并获得里面的宝物。但由于地理位置原因,有些城堡不能直接攻克,要攻克这些城堡必须先攻克其他某一个特定的城堡。你能帮ACboy算出要获得尽量多的宝物应该攻克哪M个城堡吗?
题解:
题目给的城堡形成一个森林,添加一个超级根把森林连在一起就是树了
然后跑树上背包即可
HDU2196
题目:
给你一棵树,已知每条边的权值。求每个点所能达到的最远点的距离。
题解:
经典题,前面有很像的。
hdu2546
题目:
电子科大本部食堂的饭卡有一种很诡异的设计,即在购买之前判断余额。如果购买一个商品之前,卡上的剩余金额大于或等于5元,就一定可以购买成功(即使购买后卡上余额为负),否则无法购买(即使金额足够)。所以大家都希望尽量使卡上的余额最少。 某天,食堂中有n种菜出售,每种菜可购买一次。已知每种菜的价格以及卡上的余额,问最少可使卡上的余额为多少。
题解:
贪心+动态规划(背包):
先从总钱数扣除5元,用来买最贵的菜,然后用剩余的钱来背包。
hdu5326
题目:
现在有一个有n个人的公司,然后每个人除了boss外都有一个直接领导者,然后如果是直接或间接领导的话,那么都可以说是A管理了B。然后问你有多少个人管理着k个人。
题解:
树形dp求一下