动态规划-树形动态规划

顾名思义,树型动态规划就是在“树”的数据结构上的动态规划,平时做的动态规划都是线性的或者是建立在图上的,线性的动态规划有二种方向即向前和向后,相应的线性的动态规划有二种方法即顺推与逆推,而树型动态规划是建立在树上的,所以也相应的有二个方向:

  • 根—>叶:此类动态规划在实际的问题中运用较少;
  • 叶—>根:即根的子节点传递有用的信息给根,完后根得出最优解的过程。

例:NOIP2003-加分二叉树

【问题描述】
设一个n个节点的二叉树tree的中序遍历为(1,2,3,…,n),其中数字1,2,3,…,n为节点编号。每个节点都有一个分数(均为正整数),记第i个节点的分数为di,tree及它的每个子树都有一个加分,任一棵子树subtree(也包含tree本身)的加分计算方法如下:
subtree的左子树的加分×subtree的右子树的加分+subtree的根的分数,若某个子树为空,规定其加分为1,叶子的加分就是叶节点本身的分数。不考虑它的空子树。
试求一棵符合中序遍历为(1,2,3,…,n)且加分最高的二叉树tree。要求输出:(1)tree的最高加分,(2)tree的前序遍历。

【输入格式】
第1行:一个整数n(n<30),为节点个数。
第2行:n个用空格隔开的整数,为每个节点的分数(分数<100)。
【输出格式】
第1行:一个整数,为最高加分(结果不会超过4,000,000,000)。
第2行:n个用空格隔开的整数,为该树的前序遍历。
【输入样例】(binary.in)
5
5 7 1 2 10
【输出样例】(binary.out)
145
3 1 2 4 5

【问题分析】

本题考查二叉树的遍历和动态规划算法。难点在于要记录当前最大加分二叉树的根节点。疑点是最大加分二叉树的前序遍历序列可能不唯一。很显然本题适合用动态规划来解。如果用数组f[i,j]表示从节点i到节点j所组成的二叉树的最大加分,则动态方程可以表示如下:
f[i,j]=max {f[i,i]+f[i+1,j],f[k,k]+f[i,k–1]*f[k+1,j],f[j,j]+f[i,j-1]}
题目还需输出最大加分树的前序遍历序列,因此需在计算过程中记下从节点i到节点j所组成的最大加分二叉树的根节点,用数组s[i,j]表示。

例:URAL1018-苹果二叉树
【问题描述】
有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点),这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1。我们用一根树枝两端连接的结点的编号来描述一根树枝的位置。下面是一颗有4个树枝的树:
2 5
\ /
 3 4
  \ /
   1
现在这颗树枝条太多了,需要剪枝。但是一些树枝上长有苹果。给定需要保留的树枝数量,求出最多能留住多少苹果。

【输入格式】
第1行2个数,N和Q(1<=Q<= N,1<N<=100)。N表示树的结点数,Q表示要保留的树枝数量。接下来N-1行描述树枝的信息。每行3个整数,前两个是它连接的结点的编号。第3个数是这根树枝上苹果的数量。每根树枝上的苹果不超过30000个。
【输出格式】
一个数,最多能留住的苹果的数量。
【样例输入】
5 2
1 3 1
1 4 10
2 3 20
3 5 20
【样例输出】
21

【问题分析】

因为题目一给出就是二叉的,所以很容易就可以写出方程:f[i,j]:=max{f[left[i],k-1]+f[right[i],j–k]}+a[i],0<k<=j

Function treedp(x,y:longint):longint;
VarI,j,k:longint;
Begin
 J:=0;
 For I:=0 to y do
 begin
  k:=treedp(b[x].left,I-1)+treedp(b[x].right,y-I)+a[x];
  if k>j then j:=k;
 end;
 treedp:=j;
End;

例:CTSC1997-选课

【问题描述】
在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总是在其它课程之前学习。现在有N门功课,每门课有个学分,每门课有一门或没有直接先修课(若课程a是课程b的先修课即只有学完了课程a,才能学习课程b)。一个学生要从这些课程里选择M门课程学习,问他能获得的最大学分是多少?

【输入格式】
第一行有两个整数N,M用空格隔开(1<=N<=200,1<=M<=150)
接下来的N行,第i+1行包含两个整数ki和si, ki表示第i门课的直接先修课,si表示第i门课的学分。若ki=0表示没有直接先修课(1<=ki<=N, 1<=si<=20)。
【输出格式】
只有一行,选M门课程的最大得分。
【输入样例】
7 4
2 2
0 1
0 4
2 1
7 1
7 6
2 2
【输出样例】
13

【问题分析】

这题比苹果树多了一个步骤就是把一棵普通树转化为二叉树。读入数据时把二叉树建好:第一个孩子作为父节点的左子树,其它孩子作为第一个孩子的右子树。F(x,y):表示节点x取y门课得最高学分,则:
F(x,y)=max(f(x.l,k-1)+x.v+f(x.r,y-k))k=1,2,..y
f(x.l,k-1)+x.v(课程x的学分):表示选了课程x,左孩子选k-1门课,共k门课;f (x.r,y-k):表示右孩子只能选y-k门课。节点0表示根节点,1~n是n门可选课程的节点。

例:苹果多叉树

【问题描述】
有一棵苹果树,树枝有多分叉,这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1。我们用一根树枝两端连接的结点的编号来描述一根树枝的位置。下面是一颗有4个树枝的树:
2 6 5
\  |  / 
 3 4
  \/
  1
现在这颗树枝条太多了,需要剪枝。但是一些树枝上长有苹果。给定需要保留的树枝数量,求出最多能留住多少苹果。

【问题分析】

f[i,j]:=max{f[left[i],k-1]+f[right[i],j–k]+a[k],f[right[i],j]},0<k<=j

例:URAL1039-没有上司的晚会

【问题描述】
有个公司要举行一场晚会。
为了能玩得开心,公司领导决定:如果邀请了某个人,那么一定不会邀请他的上司(上司的上司,上司的上司的上司……都可以邀请)。
每个参加晚会的人都能为晚会增添一些气氛,求一个邀请方案,使气氛值的和最大。

【输入格式】
第1行一个整数N(1<=N<=6000)表示公司的人数。
接下来N行,每行一个整数。第i行的数表示第i个人的气氛值x(-128<=x<=127)。
接下来每行两个整数L,K。表示第K个人是第L个人的上司。
输入以0 0结束。
【输出格式】
一个数,最大的气氛值和。

【问题分析】

这是树型动态规划的一种分类,每个结点都有二种状态既选与不选。f[i,1]表示邀请i的最大值,f[i,2]表示不邀请i的最大值,f[i,1]=sigma(f[i.sons,2])+a[i],f[i,2]= sigma{max(f[i.sons,1], f[i.sons,2])}。

F[i,1]=max{f[left[i],0]+f[right[i],0],f[left[i],0]+f[right[i],1]},F[I,0]=max{f[left[i],1]+f[right[i],0],f[left[i],0]+f[right[i],0]}

猜你喜欢

转载自blog.csdn.net/u013228808/article/details/85220226