文档库 最新最全的文档下载
当前位置:文档库 › 树形动态规划

树形动态规划

树形动态规划
树形动态规划

树型动态规划的实例分析

一、什么是树型动态规划

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

1.根—>叶:不过这种动态规划在实际的问题中运用的不多,也没有比较明显的例题,所以不在今天讨论的范围之内。

2.叶->根:既根的子节点传递有用的信息给根,完后根得出最优解的过程。这类的习题比较的多,下面就介绍一些这类题目和它们的一般解法。

二、例题与解析

加分二叉树

【问题描述】

设一个n个节点的二叉树tree的中序遍历为(l,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个用空格隔开的整数,为该树的前序遍历。

【输入样例】

5

5 7 1 2 10

【输出样例】

145

3 1 2

4 5

[分析]很显然,本题适合用动态规划来解。如果用数组value[i,j]表示从节点i到节点j所组成的二叉树的最大加分,则动态方程可以表示如下:

value[i,j]=max{value[i,i]+value[i+1,j],value[i+1,i+1]+value[i,i]*value[i+2,j],

value[i+2,i+2]+value[i,i+1]*value[i+3,j],…,value[j-1,j-1]+value[i,j-2]*value[j,j],

value[j,j]+value[i,j-1]}

题目还要求输出最大加分树的前序遍历序列,因此必须在计算过程中记下从节点i到节点j 所组成的最大加分二叉树的根节点,用数组root[i,j]表示

[PASCAL源程序]

{$N+}

program NOIP2003_3_Tree;

const

maxn=30;

var

i,j,n,d:byte;

a:array[1..maxn]of byte;

value:array[1..maxn,1..maxn]of comp;

root:array[1..maxn,1..maxn]of byte;

s,temp:comp;

f1,f2:text;fn1,fn2,fileNo:string;

procedure preorder(p1,p2:byte);{按前序遍历输出最大加分二叉树}

begin

if p2>=p1 then begin

write(f2,root[p1,p2],' ');

preorder(p1,root[p1,p2]-1);

preorder(root[p1,p2]+1,p2);

end;

end;

begin

write('Input fileNo:');readln(fileNo);

fn1:='tree.in'+fileNo;fn2:='tree.ou'+fileNo;

assign(f1,fn1);reset(f1);

assign(f2,fn2);rewrite(f2);

readln(f1,n);

for i:=1 to n do read(f1,a[i]);

close(f1);

fillchar(value,sizeof(value),0);

for i:=1 to n do begin

value[i,i]:=a[i];{计算单个节点构成的二叉树的加分}

root[i,i]:=i;{记录单个节点构成的二叉树的根节点}

end;

for i:=1 to n-1 do begin

value[i,i+1]:=a[i]+a[i+1];{计算相邻两个节点构成的二叉树的最大加分}

root[i,i+1]:=i;{记录相邻两个节点构成的二叉树的根节点;需要说明的是,两个节点构成的二叉树,其根节点可以是其中的任何一个;这里选编号小的为根节点,则编号大的为其右子树;若选编号大的为根节点,则编号小的为其左子树;因此,最后输出的前序遍历结果会有部分不同,但同样是正确的。如果最大加分二叉树的所有节点的度数都是0或2,则最后输出的前序遍历结果是唯一的。}

end;

for d:=2 to n-1 do begin{依次计算间距为d的两个节点构成的二叉树的最大加分}

for i:=1 to n-d do begin

s:=value[i,i]+value[i+1,i+d];{计算以i为根节点,以i+1至i+d间所有节点为右子树的二叉树的最大加分}

root[i,i+d]:=i; {记录根节点i}

for j:=1 to d do begin

temp:=value[i+j,i+j]+value[i,i+j-1]*value[i+j+1,i+d];{计算以i+j为根节点,以i至i+j-1间所有节点为左子树,以i+j+1至i+d间所有节点为右子树的二叉树的最大加分} if temp>s then begin{如果此值为最大}

s:=temp;root[i,i+d]:=i+j;{记下新的最大值和新的根节点}

end;

end;

temp:=value[i,i+d-1]+value[i+d,i+d];{计算以i+d为根节点,以i至i+d-1间所有节点为左子树的二叉树的最大加分}

if temp>s then begin

s:=temp;root[i,i+d]:=i+d+1;

end;

value[i,i+d]:=s;

end;

end;

writeln(f2,value[1,n]:0:0);{输出最大加分}

preorder(1,n);{输出最大加分二叉树的前序遍历序列}

close(f2);

end.

[点评]基本题。考查了二叉树的遍历和动态规划算法。难点在于要记录当前最大加分二叉树的根节点。疑点是最大加分二叉树的前序遍历序列可能不唯一。

Ps:其实这题真正意义上来说还是一道普通的dp题目,但它批上了树的外表,所以都拿来作对比和讨论,解题报告出自湖北省水果湖高中伍先军写的第九届全国青少年信息学奥林匹克联赛(N0IP2003)复赛提高组解题报告。

Ural 1018 二*苹果树

题目

有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点)

这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1。

我们用一根树枝两端连接的结点的编号来描述一根树枝的位置。下面是一颗有4个树枝的树 2 5

\ /

3 4

\ /

1

现在这颗树枝条太多了,需要剪枝。但是一些树枝上长有苹果。

给定需要保留的树枝数量,求出最多能留住多少苹果。

输入格式

第1行2个数,N和Q(1<=Q<= N,1

N表示树的结点数,Q表示要保留的树枝数量。接下来N-1行描述树枝的信息。

每行3个整数,前两个是它连接的结点的编号。第3个数是这根树枝上苹果的数量。

每根树枝上的苹果不超过30000个。

输出格式

一个数,最多能留住的苹果的数量。

样例输入

5 2

1 3 1

1 4 10

2 3 20

3 5 20

样例输出

21

解析:因为题目一给出就是二叉的,所以很容易就可以写出方程:

a(I,j):=max(a(i.left,k)+a(i.right,j-k)),0<=k<=j

源程序代码:

由于比较简单便不给完全的代码了。

Function treedp(x,y:longint):longint;

Var I,j,k:longint;

Begin

J:=0;

For I:=0 to y do

begin

k:=treedp(b[x].l,I)+treedp(b[x].r,y-I);

if k>j then j:=k;

end;

treedp:=j;

End;

选课

[问题描述]

在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在

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

输入:

第一行有两个整数N,M用空格隔开。(1<=N<=200,1<=M<=150)

接下来的N行,第I+1行包含两个整数k i和s i, k i表示第I门课的直接先修课,s i表示第I 门课的学分。若k i=0表示没有直接先修课(1<=k i<=N, 1<=s i<=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=0,1,..y

f(x.l,k-1)+x.v(课程x的学分) :表示选了课程x,左孩子选k-1门课,共k门课。

f (x.r,y-k)表示右孩子只能选y-k门课。

标程中节点-1表示空节点,0是根节点,1—n是n门可选课程的节点.

思考:若本题加上选那些课程可得到这个最大学分,怎样修改程序?

实现:

怎么实现,是在竞赛中的很重要的一个问题,如果你想ac了这道题目的话,你应该熟悉怎么把一棵树转化成二叉树,完后怎么用递规的思想来实现动态规划。所以坚实的基础是很重要的东西,如果没有了基础,什么都是空中楼阁。

程序中已经边读边把二叉树建立好了。

源程序代码:

program bluewater;

type

tree=record

l,r,k:longint;

end;

var

s:string;

i,j,k,l:longint;

n,m:longint;

a:array[0..200] of tree;

b:array[-1..200,0..150] of integer;

f:array[0..200] of longint;

procedure treedp(x,y:longint);

var i,j,k,l:longint;

begin

if b[x,y]>=0 then exit;

treedp(a[x].r,y);{只有右子树的情况}

j:=b[a[x].r,y];

for k:=1 to y do{左右子树都有的情况}

begin

treedp(a[x].l,k-1);

treedp(a[x].r,y-k);

i:=b[a[x].l,k-1]+b[a[x].r,y-k]+a[x].k;

if i>j then j:=i;

end;

b[x,y]:=j;

end;

begin

readln(s);

assign(input,s);reset(input);

readln(n,m);

fillchar(f,sizeof(f),0);

for i:=0 to n do

begin a[i].l:=-1;a[i].r:=-1;a[i].k:=-1;end; {build tree}

for i:=1 to n do

begin

readln(k,l);

a[i].k:=l;

if f[k]=0 then a[k].l:=i

else a[f[k]].r:=i;

f[k]:=i;

end;

{bianjie}

for i:=-1 to n do

for j:=-1 to m do

if (i=-1) or (j=0) then b[i,j]:=0 else b[i,j]:=-1; {tree dp}

treedp(a[0].l,m);

{output}

writeln(b[a[0].l,m]);

end.

Tju1053 技能树

Problem

玩过Diablo的人对技能树一定是很熟悉的。一颗技能树的每个结点都是一项技能,要学会这项技能则需要耗费一定的技能点数。

只有学会了某一项技能以后,才能继续学习它的后继技能。每项技能又有着不同的级别,级别越高效果越好,而技能的升级也是

需要耗费技能点数的。

有个玩家积攒了一定的技能点数,他想尽可能地利用这些技能点数来达到最好的效果。因此他给所有的级别都打上了分,他认为

效果越好的分数也越高。现在他要你帮忙寻找一个分配技能点数的方案,使得分数总和最高。

Input

该题有多组测试数据。

每组测试数据第一行是一个整数n(1<=n<=20),表示所有不同技能的总数。

接下来依次给出n个不同技能的详细情况。

每个技能描述包括5行。

第一行是该技能的名称。

第2行是该技能在技能树中父技能的名称,名称为None则表示该技能不需要任何的先修技能便能学习。

第3行是一个整数L(1<=L<=20),表示这项技能所能拥有的最高级别。

第4行共有L个整数,其中第I个整数表示从地I-1级升到第I级所需要的技能点数(0级表示没有学习过)。

第5行包括L个整数,其中第I个整数表示从第I-1级升级到第I级的效果评分,分数不超过20。

在技能描述之后,共有两行,第1行是一个整数P,表示目前所拥有的技能点数。

接下来1行是N个整数,依次表示角色当前习得的技能级别,0表示还未学习。这里不会出现非法情况。

Output

每组测试数据只需输出最佳分配方案所得的分数总和。

Sample Input

3

Freezing Arrow

Ice Arrow

3

3 3 3

15 4 6

Ice Arrow

Cold Arrow

2

4 3

10 17

Cold Arrow

None

3

3 3 2

15 5 2

10

0 0 1

Sample Output

42

Source

浙江省2004组队赛第二试

解析:这题是选课的加强版,但并难不倒我们

还是把一棵树转换为二叉树,完后从子节点到根节点作一次dp,最后得到最优解由于和上题很相像就不写方程了。

源代码程序:

program bluewater;

type

tree=record

s,sf:string;

l,r,m:longint;

c:array[1..20] of longint;

d:array[1..20] of longint;

end;

var

i,j,k,l,m,n:longint;

a:array[0..20] of tree;

b:array[0..20] of longint;

learn:array[0..20] of longint;

f:array[0..20,0..8000] of longint;

function treedp(x,y:longint):longint;

var i,j,k,l,max,o,p,q:longint;

begin

if f[x,y]<>-1 then begin treedp:=f[x,y];exit;end; max:=treedp(a[x].r,y);

{learn>0}

if learn[x]>0 then

begin

for k:=0 to y do

begin

i:=treedp(a[x].l,k)+treedp(a[x].r,y-k);

if i>max then max:=i;

end;

end;

{learn=0}

l:=0;p:=0;i:=0;

for o:=1 to a[x].m do

begin

if o>learn[x] then

begin l:=l+a[x].c[o];p:=p+a[x].d[o];end;

for k:=0 to y-l do

begin

i:=treedp(a[x].l,k)+treedp(a[x].r,y-l-k)+p;

if i>max then max:=i;

end;

end;

f[x,y]:=max;

treedp:=max;

end;

function find(x:string):longint;

var i,j:longint;

begin

for i:=0 to n do

if a[i].s=x then break;

find:=i;

end;

begin

while not(eof(input)) do

begin

{input}

readln(n);

fillchar(a,sizeof(a),0);

fillchar(b,sizeof(b),0);

a[0].s:='None';

for i:=1 to n do

with a[i] do

begin

readln(s);

readln(sf);

readln(m);

for j:=1 to m do read(c[j]);readln;

for j:=1 to m do read(d[j]);readln;

end;

readln(m);

if m>8000 then m:=8000;

for i:=1 to n do read(learn[i]);readln;

{build binary tree}

for i:=1 to n do

begin

k:=find(a[i].sf);

if b[k]=0 then

begin b[k]:=i;a[k].l:=i;end

else begin a[b[k]].r:=i;b[k]:=i;end;

end;

{bian jie}

for i:=0 to 20 do

for j:=0 to 8000 do

f[i,j]:=-1;

for i:=0 to 8000 do f[0,i]:=0;

{main}

writeln(treedp(a[0].l,m));

end;

end.

战略游戏

Problem

Bob喜欢玩电脑游戏,特别是战略游戏。但是他经常无法找到快速玩过游戏的办法。现在他有个问题。

他要建立一个古城堡,城堡中的路形成一棵树。他要在这棵树的结点上放置最少数目的士兵,使得这些士兵能了望到所有的路。

注意,某个士兵在一个结点上时,与该结点相连的所有边将都可以被了望到。

请你编一程序,给定一树,帮Bob计算出他需要放置最少的士兵.

Input

第一行为一整数M,表示有M组测试数据

每组测试数据表示一棵树,描述如下:

第一行 N,表示树中结点的数目。

第二行至第N+1行,每行描述每个结点信息,依次为:该结点标号i,k(后面有k条边与结点I相连)。

接下来k个数,分别是每条边的另一个结点标号r1,r2,...,rk。

对于一个n(0

Output

输出文件仅包含一个数,为所求的最少的士兵数目。

例如,对于如下图所示的树:

答案为1(只要一个士兵在结点1上)。

Sample Input

2

4

0 1 1

1 2 2 3

2 0

3 0

5

3 3 1

4 2

1 1 0

2 0

0 0

4 0

Sample Output

1

2

Source

sgoi

分析:这题有2种做法,一种是比较简单但不是很严密的贪心,如果测试数据比较刁钻的话

就不可能ac,而这题是一道比较典型的树型动态规划的题目,这题不但要考虑子节点对他的根节点的影响,而且每放一个士兵,士兵所在位置既影响他的子节点也影响了他的根节点。不过状态还是很容易来表示的,动规实现也不是很难,不过这在这些例题中也有了些“创新”了。而且这题不是一个对二叉树的dp,而是对一颗普通树的dp,所以更具代表性。

源程序代码:

program bluewater;

const

maxn=1500;

var

i,j,k,l:longint;

m,n,p,q:longint;

a:array[0..maxn,0..maxn] of boolean;

b:array[0..maxn] of longint;

c:array[0..maxn] of boolean;

function leaf(x:longint):boolean;

var i,j:longint;

t:boolean;

begin

t:=true;

for i:=0 to n-1 do

if a[x,i] then begin t:=false;break;end;

leaf:=t;

end;

function treedp(x:longint):longint;

var i,j,k,l:longint;

begin

j:=0;{add}

k:=0;{leaf}

l:=0;{not put not leaf}

for i:=0 to n-1 do

if (a[x,i]) and (x<>i) then

if leaf(i) then inc(k) else

begin

j:=j+treedp(i);

if not(c[i]) then inc(l);

end;

{puanduan}

if (k>0) or (l>0) then begin c[x]:=true;treedp:=j+1;exit;end;

if (j>0) and (l=0) then begin treedp:=j;exit;end;

end;

begin

{input}

readln(m);

for p:=1 to m do

begin

fillchar(b,sizeof(b),0);

fillchar(a,sizeof(a),false);

fillchar(c,sizeof(c),false);

readln(n);

for i:=1 to n do

begin

read(k,l);

for j:=1 to l do

begin

read(q);

a[k,q]:=true;

b[q]:=1;

end;

readln;

end;

{main}

for i:=0 to n-1 do

if b[i]=0 then break;

fillchar(b,sizeof(b),0);

if leaf(i) then writeln('1') else writeln(treedp(i));

end;

end.

Ural 1039 没有上司的晚会

背景

有个公司要举行一场晚会。

为了能玩得开心,公司领导决定:如果邀请了某个人,那么一定不会邀请他的上司(上司的上司,上司的上司的上司……都可以邀请)。

题目

每个参加晚会的人都能为晚会增添一些气氛,求一个邀请方案,使气氛值的和最大。

输入格式

第1行一个整数N(1<=N<=6000)表示公司的人数。

接下来N行每行一个整数。第i行的数表示第i个人的气氛值x(-128<=x<=127)。接下来每行两个整数L,K。表示第K个人是第L个人的上司。

输入以0 0结束。

输出格式

一个数,最大的气氛值和。

样例输入

7

1

1

1

1

1

1

1

1 3

2 3

6 4

7 4

4 5

3 5

0 0

样例输出

5

http://acm.timus.ru/submit.aspx?space=1&num=1039

分析:

f[i,1]表示邀请i的最大值

f[i,2]表示不邀请i的最大值

f[i,1]=sigma(f[i.sons,2])

f[i,2]=sigma(max{f[i.sons,1],f[i.sons,2]})

这个又是树型动态规划的一种分类,每个结点都有二种状态既选与不选。

总结:看完了上面的这些关于叶子->根的树型动态规划,我想您已经对这种treedp有了一些了解,其实一样新的东西你并不该去怕它而是坦然的面对,树型动态规划也就是动态规划的一种,再怎么也走不出动态规划的范围,只要充分了解了树的结构后,树型动态规划还是很好实现的。

参考资料

1.第九届全国青少年信息学奥林匹克联赛(N0IP2003)复赛提高组解题报告——伍先军

树形DP之个人整理总结

树形DP 二叉苹果树(ural 1108) 题目意思: 有一棵苹果树,苹果树的是一棵二叉树,共N个节点,树节点编号为1~N,编号为1的节点为树根,边可理解为树的分枝,每个分支都长着若干个苹果,现在要要求减去若干个分支,保留M个分支,要求这M个分支的苹果数量最多。 输入: N M 接下来的N-1行是树的边,和该边的苹果数N and M (1 ≤ M < N; 1 < N ≤ 100) 输出: 剩余苹果的最大数量。 input 5 2 1 3 1 1 4 10 2 3 20 3 5 20 output 21 算法: 删除了某个分支,那么这个分支下的子分支也同时删除。 保留M个分支,也就是删除N-M-1个分支。剩余的最多苹果数=总苹果数-剪掉的苹果数。注意本题给的边并没有按照树根--树叶的形式来给,也没有按照树的顺序给出边。本来想一个节点对应一个分支长着的苹果数量,cost[v]就表示v这个节点的苹果数,可以这样做,但是在输入的时候,不知道这个苹果数量是那个节点的,因为不知道哪个是哪个的子结点。所以用了无向图和苹果数加到边上去。 我的解法中:这题的树状DP的整体思想个pku3345是一样的。 有一些不一样的地方要注意一下: 本程序其实不仅仅针对二叉树,可以是任意的树,删除任意个分支都有算。 #include #include #include using namespace std; #define MN 110 int f[2*MN],p[MN],tmp[MN];

int N,M; bool visit[MN]; struct NODE { int val; int cost; }; vectorG[MN]; inline int max(int a,int b) { return a>b?a:b; } inline int min(int a,int b) { return a

动态规划专题(六):树型动态规划

动态规划专题(六):树型动态规划 (重庆巴蜀中学黄新军) 信息学竞赛中通常会出现这样的问题:给一棵树,要求以最少的代价(或取得最大收益)完成给定的操作。有很多问题都是在树和最优性的基础上进行了扩充和加强,从而变成了棘手的问题。这类问题通常规模较大,枚举算法的效率无法胜任,贪心算法不能得到最优解,因此要用动态规划解决。 和一般动态规划问题一样,这类问题的解决要考虑如下三步: 1、确立状态:几乎所以的问题都要保存以某结点为根的子树的情况,但是要根据具体问题考虑是否要加维,加几维,如何加维。 2、状态转移:状态转移的变化比较多,要根据具体问题具体分析,这也是本文例题分析的重点。 3、算法实现: 由于模型建立在树上,即为树型动态规划。 【例题1】二叉苹果树 【问题描述】 有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点),这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1。 我们用一根树枝两端连接的结点的编号来描述一根树枝的位置。下面是一颗有4个树枝的树: 现在这颗树枝条太多了,需要剪枝。但是一些树枝上长有苹果。给定需要保留的树枝数量,求出最多能留住多少苹果。 【文件输入】 第1行2个数,N和Q(1<=Q<=N,1

最新英语语言学树型图详细讲解

树形图详细讲解 1. Indicate the category of each word in the following sentences. a) The old lady suddenly left. Det A N Qual V b) The car stopped at the end of the road. Det N V P Det N P Det N c) The snow might have blocked the road. Det N Aux Aux V Det N d) He never appears quite mature. N Qual V Deg A 2. The following phrases include a head, a complement, and a specifier. Draw the appropriate tree structure for each. a) full of people AP A P N full of people b) a story about a sentimental girl NP NP PP Det N P NP Det A N a story about a sentimental girl c) often read detective stories VP Qual V NP A N often read detective stories

d) the argument against the proposals NP NP PP Det N P NP Det N the argument against the proposals e) move towards the window VP V PP P Det N move towards the window 3. Draw phrase structure trees for each of the following sentences. a) The jet landed. InflP(=S) NP Infl VP Det N Pst V The jet landed b) Mary became very ill. InflP(=S) NP Infl VP N Pst V AP Deg A Mary became very ill

最优二叉查找树_动态规划

最优二叉查找树 【源程序】 //本程序测试用例为课本例题 #include #define INF 1000000000 //将这两个二维数组定义为全局变量,从而可以避免在函数之间进行参数的传递double C[100][100]; int R[100][100]; doubleOptimalBST(double p[], int n) { inti, j, k, d; int mink; //注意这里min 和sum一定要定义成double类型,否则赋不上值!!doublemin,sum; for(i=1; i<=n; i++) { C[i][i-1]=0; C[i][i]=p[i-1]; R[i][i]=i; } C[n+1][n]=0; for(d=1; d

} return C[1][n]; } int main() { int n; double p[100]; printf("请输入字符个数:"); scanf("%d",&n); printf("\n"); printf("请输入每个字符的查找概率:"); for(inti=0; i

动态规划状态转移方程

1.资源问题1 -----机器分配问题 F[I,j]:=max(f[i-1,k]+w[i,j-k]) 2.资源问题2 ------01背包问题 F[I,j]:=max(f[i-1,j-v[i]]+w[i],f[i-1,j]); 3.线性动态规划1 -----朴素最长非降子序列 F[i]:=max{f[j]+1} 4.剖分问题1 -----石子合并 F[i,j]:=min(f[i,k]+f[k+1,j]+sum[i,j]); 5.剖分问题2 -----多边形剖分 F[I,j]:=min(f[i,k]+f[k,j]+a[k]*a[j]*a[i]); 6.剖分问题3 ------乘积最大 f[i,j]:=max(f[k,j-1]*mult[k,i]); 7.资源问题3 -----系统可靠性(完全背包) F[i,j]:=max{f[i-1,j-c[i]*k]*P[I,x]} 8.贪心的动态规划1 -----快餐问题 F[i,j,k]:=max{f[i-1,j',k']+(T[i]-(j-j')*p1-(k-k')*p2) div p3} 9.贪心的动态规划2 -----过河 f[i]=min{{f(i-k)} (not stone[i]) {f(i-k)}+1} (stone[i]); +贪心压缩状态 10.剖分问题4 -----多边形-讨论的动态规划 F[i,j]:=max{正正 f[I,k]*f[k+1,j]; 负负 g[I,k]*f[k+1,j]; 正负 g[I,k]*f[k+1,j]; 负正 f[I,k]*g[k+1,j];} g为min 11.树型动态规划1 -----加分二叉树 (从两侧到根结点模型)

动态规划基本原理

动态规划基本原理 近年来,涉及动态规划的各种竞赛题越来越多,每一年的NOI几乎都至少有一道题目需要用动态规划的方法来解决;而竞赛对选手运用动态规划知识的要求也越来越高,已经不再停留于简单的递推和建模上了。 要了解动态规划的概念,首先要知道什么是多阶段决策问题。 一、多阶段决策问题 如果一类活动过程可以分为若干个互相联系的阶段,在每一个阶段都需作出决策(采取措施),一个阶段的决策确定以后,常常影响到下一个阶段的决策,从而就完全确定了一个过程的活动路线,则称它为多阶段决策问题。 各个阶段的决策构成一个决策序列,称为一个策略。每一个阶段都有若干个决策可供选择,因而就有许多策略供我们选取,对应于一个策略可以确定活动的效果,这个效果可以用数量来确定。策略不同,效果也不同,多阶段决策问题,就是要在可以选择的那些策略中间,选取一个最优策略,使在预定的标准下达到最好的效果. 让我们先来看下面的例子:如图所示的是一个带权有向的多段图,要求从A到D的最短 图4-1 带权有向多段图 路径的长度(下面简称最短距离)。 我们可以搜索,枚举图中的每条路径,但当图的规模大起来时,搜索的效率显然不可能尽人意。让我们来试用动态规划的思路分析这道题:从图中可以看到,A点要到达D点必然要经过B1和B2中的一个,所以A到D的最短距离必然等于B1到D的最短距离加上5,或是B2到D的最短距离加上2。同样的,B1到D的最短距离必然等于C1到D的最短距离加上3或是C2到D的最短距离加上2,……。 我们设G[i]为点i到点D的距离,显然G[C1]=4,G[C2]=3,G[C3]=5,根据上面的分析,

有: G[B1]=min{G[C1]+3,G[C2]+2}=5, G[B2]=min{G[C2]+7,G[C3]+4}=9, 再就有G[A]=min{G[B1]+5,G[B2]+2}=10, 所以A到D的最短距离是10,最短路径是A→B1→C2→D。 二、动态规划的术语 1.阶段 把所给求解问题的过程恰当地分成若干个相互联系的阶段,以便于求解,过程不同,阶段数就可能不同.描述阶段的变量称为阶段变量。在多数情况下,阶段变量是离散的,用k 表示。此外,也有阶段变量是连续的情形。如果过程可以在任何时刻作出决策,且在任意两个不同的时刻之间允许有无穷多个决策时,阶段变量就是连续的。 在前面的例子中,第一个阶段就是点A,而第二个阶段就是点A到点B,第三个阶段是点B到点C,而第四个阶段是点C到点D。 2.状态 状态表示每个阶段开始面临的自然状况或客观条件,它不以人们的主观意志为转移,也称为不可控因素。在上面的例子中状态就是某阶段的出发位置,它既是该阶段某路的起点,同时又是前一阶段某支路的终点。 在前面的例子中,第一个阶段有一个状态即A,而第二个阶段有两个状态B1和B2,第三个阶段是三个状态C1,C2和C3,而第四个阶段又是一个状态D。 过程的状态通常可以用一个或”一组数”来描述,称为状态变量。一般,状态是离散的,但有时为了方便也将状态取成连续的。当然,在现实生活中,由于变量形式的限制,所有的状态都是离散的,但从分析的观点,有时将状态作为连续的处理将会有很大的好处。此外,状态可以有多个分量(多维情形),因而用向量来代表;而且在每个阶段的状态维数可以不同。 当过程按所有可能不同的方式发展时,过程各段的状态变量将在某一确定的范围内取值。状态变量取值的集合称为状态集合。 3.无后效性 我们要求状态具有下面的性质:如果给定某一阶段的状态,则在这一阶段以后过程的发

树形动规题型分析

树形动规题型分析北京大学李煜东

Ural1039 没有上司的舞会 题目大意:Ural大学有N个职员,编号为1~N。他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。每个职员有一个快乐指数。现在有个周年庆宴会,要求与会职员的快乐指数最大。但是,没有职员愿和直接上司一起与会。 F[i][0]表示以i为根的子树,i不参加舞会时的最大快乐指数。 F i0= s∈Son i Max(F s0,F[s][1]) F[i][1]表示以i为根的子树,i参加舞会时的最大快乐指数。 F i1=Happy i+ s∈Son i F s0 通过DFS求出F数组,目标就是Max(F[1][0],F[1][1])。

Nescafé8 创世纪 题目大意:上帝手中有着N(N<=1000000)种被称作“世界元素”的东西,现在他要把它们中的一部分投放到一个新的空间中去建造世界。每种世界元素都可以限制另外一种世界元素,上帝希望所有被投放的世界元素都有至少一个没有被投放的世界元素能够限制它。 上帝希望知道他最多可以投放多少种世界元素? 每个世界元素的出度都是1(只能限制另外一种),所以题目中的限制条件构成内向树森林。 如果题目中的限制条件构成的图是一棵树,那么DP方法和上一题类似:F[i][0]表示i没有被投放时,以i为根的子树里最多可以投放多少种世界元素。 F[i][1]表示i被投放时,以i为根的子树里最多可以投放多少种世界元素。 F i0=s∈Son i Max(F s0,F[s][1]) F i1=Max F s0+s′∈Son i,s′≠s Max F s′0,F s′1|s∈Son i 如果是内向树,那么任意枚举基环上的一条边,先把它断开(不使用这个限制条件),在剩余的树上进行树状动规;然后再强制使用这个限制条件,再进行一次树状动规。

语言学树形图课后问题详解

文档 树形图详细讲解 网上的相对理想的树形图答案,注意正两点: 1.短语和中心词在一竖线上 2.含有形容词修饰语的名词短语的画法 NP Det N A N a little boy 1. Indicate the category of each word in the following sentences. a)T he old lady suddenly left. Det A N Qual V b)The car stopped at the end of the road. Det N V P Det N P Det N c)T he snow might have blocked the road. Det N Aux Aux V Det N d)H e never appears quite mature. N Qual V Deg A 2.T he following phrases include a head, a complement, and a specifier. Draw the appropriate tree structure for each. a) full of people AP A P N

文档full of people b)a story about a sentimental girl NP NP PP Det N P NP Det A N a story about a sentimental girl c)o ften read detective stories VP Qual V NP A N often read detective stories

语言学树形图课后问题详细讲解

树形图详细讲解 网上的相对理想的树形图答案,注意正两 点: 1. 短语和中心词在一竖线上 2. 含有形容词修饰语的名词短语的画法 NP Det N A N a little boy 1. Indicate the category of each word in the following sentences. a) The old lady suddenly left. Det A N Qual V b) The car stopped at the end of the road. Det N V P Det N P Det N c) The snow might have blocked the road.

Det N Aux Aux V Det N d) He never appears quite mature. N Qual V Deg A 2. The following phrases include a head, a complement, and a specifier. Draw the appropriate tree structure for each. a) full of people AP A P N full of people b) a story about a sentimental girl NP NP PP

Det N P NP Det A N a story about a sentimental girl c) often read detective stories VP Qual V NP A N often read detective stories

试题(树型动规)

1.加分二叉树(binary.c/cpp) NOIP2003提高组第3题 【问题描述】 设一个n个节点的二叉树tree的中序遍历为(l,2,3,…,n),其中数字1,2,3,…,n为节点编号。每个节点都有一个分数(均为正整数),记第j个节点的分数为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个用空格隔开的整数,为该树的前序遍历。 【输入样例】 5 5 7 1 2 10 【输出样例】 145 3 1 2 4 5 F(I,j) I,i+1…..j 枚举K(根结点) F(I,j)=max{d[k]+f[I,K-1]*f[K+1,j]} 1…I K…..j…..n F(I,i)=d[k] F(1,n)\ 边界:空树和只含有一个结点的树 自底向上递归前序遍历(根-左-右)二维数组记录决策 时间复杂度:I j K N3 30*30*30=27000 最高加分:4*109 int 2.1*109long float double(双精度)

最优二叉查找树(动态规划)

一、什么是最优二叉查找树 最优二叉查找树: 给定n个互异的关键字组成的序列K=,且关键字有序(k1

概率分布: i012345 p i0.150.100.050.100.20 q i0.050.100.050.050.050.10 已知每个关键字以及虚拟键被搜索到的概率,可以计算出一个给定二叉查找树内一次搜索的期望代价。假设一次搜索的实际代价为检查的节点的个数,即所发现的节点的深度加1.计算一次搜索的期望代价等式为: 建立一棵二叉查找树,如果是的上式最小,那么这棵二叉查找树就是最优二叉查找树。 而且有下式成立: 二、最优二叉查找树的最优子结构 最优子结构: 如果一棵最优二叉查找树T有一棵包含关键字ki,..,kj的子树T',那么这可子树T'对于关键字Ki,...,kj和虚拟键di-1,...dj的子问题也必定是最优的。可以应用剪贴法证明。

动态规划 最优二叉搜索树

摘要 动态规划算法通常用于求解具有某种最优性质的问题。在这类问题中,可能会有许多可行解,每个解都对应一个值,要求找到具有最优值的解。其基本思想是将待求解问题分解成若干个子问题,先求解子问题,并把所有已解子问题的答案记录到一个表中,而不考虑这些子问题的答案以后是否被用到。用动态规划算法来求解最优二叉搜索树问题,可以描述为对于有序集S及S的存取概率分布(a0,b1,a1,…, bn,an),在所有表示有序集S的二叉搜索树中找出一棵开销最小的二叉搜索树。 动态规划算法的有效性依赖于问题本身具有最优子结构性质和子问题重叠性质。最典型的就是路由器中的路由搜索引擎查找一条指定的路由最坏情况下最多只用查找31次。 该文给出了用动态规划算法构造最优二叉搜索树的详细步骤,并用C++语言具体实现了该算法,用一定的空间换取时间,提高了解决本问题的效率。 关键词:动态规划,最优二叉搜索树,最优子结构

目录 1 问题描述 (1) 2 问题分析 (2) 3 算法设计 (3) 4 算法实现 (4) 5 测试分析 (6) 结论 (7) 参考文献 (8)

1 问题描述 给定一个有序序列K={k1

百个经典动态规划转移方程

1. 资源问题1 -----机器分配问题 F[I,j]:=max(f[i-1,k]+w[i,j-k]) 2. 资源问题2 ------01背包问题 F[I,j]:=max(f[i-1,j-v[i]]+w[i],f[i-1,j]); 3. 线性动态规划1 -----朴素最长非降子序列 F[i]:=max{f[j]+1} 4. 剖分问题1 -----石子合并 F[i,j]:=min(f[i,k]+f[k+1,j]+sum[i,j]); 5. 剖分问题2 -----多边形剖分 F[I,j]:=min(f[i,k]+f[k,j]+a[k]*a[j]*a[i]); 6. 剖分问题3 ------乘积最大 f[i,j]:=max(f[k,j-1]*mult[k,i]); 7. 资源问题3 -----系统可靠性(完全背包) F[i,j]:=max{f[i-1,j-c[i]*k]*P[I,x]} 8. 贪心的动态规划1 -----快餐问题 F[i,j]表示前i条生产线生产j个汉堡,k个薯条所能生产的最多饮料, 则最多套餐ans:=min{j div a,k div b,f[I,j,k] div c} F[i,j,k]:=max{f[i-1,j',k']+(T[i]-(j-j')*p1-(k-k')*p2) div p3} 9. 贪心的动态规划2 -----过河 f[i]=min{{f(i-k)} (not stone[i]) {f(i-k)}+1} (stone[i]); +贪心压缩状态 10. 剖分问题4 -----多边形-讨论的动态规划 F[i,j]:=max{正正 f[I,k]*f[k+1,j]; 负负 g[I,k]*f[k+1,j]; 正负 g[I,k]*f[k+1,j];

信息学奥赛——树型动态规划的实例分析

全国青少年信息学奥林匹克联赛 树型动态规划的实例分析 一、什么是树型动态规划 顾名思义,树型动态规划就是在“树”的数据结构上的动态规划,平时作的动态规划都是线性的或者是建立在图上的,线性的动态规划有二种方向既向前和向后,相应的线性的动态规划有二种方法既顺推与逆推,而树型动态规划是建立在树上的,所以也相应的有二个方向: 1.根—>叶:不过这种动态规划在实际的问题中运用的不多,也没有比较明显的例题,所以不在今天讨论的范围之内。 2.叶->根:既根的子节点传递有用的信息给根,完后根得出最优解的过程。这类的习题比较的多,下面就介绍一些这类题目和它们的一般解法。 二、例题与解析 加分二叉树 【问题描述】 设一个n个节点的二叉树tree的中序遍历为(l,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个用空格隔开的整数,为该树的前序遍历。 【输入样例】 5 5 7 1 2 10 【输出样例】 145 3 1 2 4 5 [分析]很显然,本题适合用动态规划来解。如果用数组value[i,j]表示从节点i到节点j 所组成的二叉树的最大加分,则动态方程可以表示如下: value[i,j]=max{value[i,i]+value[i+1,j],value[i+1,i+1]+value[i,i]*value[i+2,j], value[i+2,i+2]+value[i,i+1]*value[i+3,j],…,value[j-1,j-1]+value[i,j- 2]*value[j,j], value[j,j]+value[i,j-1]} 题目还要求输出最大加分树的前序遍历序列,因此必须在计算过程中记下从节点i到节点j所组成的最大加分二叉树的根节点,用数组root[i,j]表示 [PASCAL源程序] {$N+} program NOIP2003_3_Tree; const maxn=30; var i,j,n,d:byte; a:array[1..maxn]of byte; value:array[1..maxn,1..maxn]of comp; root:array[1..maxn,1..maxn]of byte; s,temp:comp; f1,f2:text;fn1,fn2,fileNo:string; procedure preorder(p1,p2:byte);{按前序遍历输出最大加分二叉树}

相关文档
相关文档 最新文档