【原题】【noip 2003 T2】【动态规划】加分二叉树
問題
描述 Description
設一個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的前序遍歷
輸入格式 Input Format
第1行:一個整數n(n<30),為節點個數。
第2行:n個用空格隔開的整數,為每個節點的分數(分數<100)。
輸出格式 Output Format
第1行:一個整數,為最高加分(結果不會超過4,000,000,000)。
第2行:n個用空格隔開的整數,為該樹的前序遍歷。
?
分析
一看就是一道動態規劃,而且是樹形的。仔細分析題意我們發先中序遍歷的遍歷順序是——左根右。也就是說,一旦根的位置在一個中序遍歷之中確定,它的左邊的序列就是它的左子樹,右邊就是右子樹。那么整棵樹的最優值就是左子樹的最優值乘上右子樹的最優值。
我們可以得到方程:f[i,j]表示中序遍歷中i~j這棵子樹能得到的最大加分 f[i,j]=max{f[i,k-1]*f[k+1,j]+f[k,k]}(i<=k<=j)方程一定要這么寫,因為我們要考慮子樹為空的情況,所以i到j中的任意一個點都可以作為這棵樹的根。循環時要先循環區間長度l,這就類似于區間類的動態規劃了,為什么呢。因為對于一個樹形的動態規劃,都是從下至上的。所以要先找到葉子節點,再逐層找到根節點。
邊界處理:將所有空子樹的值都賦為1。
反思
方程的正確性直接影響結果。有的時候方程不能改動,根題目的要求和數據結構有關,要保證方程的正確性,保證每一步的最優性。不同類型的動態規劃有相同的地方,其宗旨是無后效性和子結構最優性。
code
program liukee; varpath,f:array[0..50,0..50] of longint;i,n,j,k,l:longint;procedure outit(x,y:longint); beginif x>y then exit;write(path[x,y],' ');outit(x,path[x,y]-1);outit(path[x,y]+1,y); end;beginfilldword(f,sizeof(f)>>2,1);readln(n);for i:=1 to n dobeginread(f[i,i]);path[i,i]:=i;end;for l:=2 to n dofor i:=1 to n-1 dobeginj:=i+l-1;for k:=i to j doif f[i,k-1]*f[k+1,j]+f[k,k]>f[i,j] thenbeginf[i,j]:=f[i,k-1]*f[k+1,j]+f[k,k];path[i,j]:=k;end;end;writeln(f[1,n]);outit(1,n); end.轉載于:https://www.cnblogs.com/liukeke/archive/2010/11/16/1878515.html
總結
以上是生活随笔為你收集整理的【原题】【noip 2003 T2】【动态规划】加分二叉树的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: uml 中的小人
- 下一篇: 用Ant编译Flex项目的几点注意事项