DP - 區間DP(求具體方案) - NOIP 2003 - 加分二叉樹

DP - 區間DP - NOIP 2003 - 加分二叉樹

設一個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,爲節點個數。

第2行:n個用空格隔開的整數,爲每個節點的分數(0<分數<100)。

輸出格式
第1行:一個整數,爲最高加分(結果不會超過4,000,000,000)。

第2行:n個用空格隔開的整數,爲該樹的前序遍歷。如果存在多種方案,則輸出字典序最小的方案。

數據範圍
n<30

輸入樣例:
5
5 7 1 2 10
輸出樣例:
145
3 1 2 4 5

分析:

DP二叉樹的左右子樹的收益的計算是相互獨立的,因此可以考慮區間DP。

由於劃分爲左右子樹來計算收益,因此可以枚舉根節點爲分界點。

f[i][j]:[i,j]狀態表示:f[i][j]:區間[i,j]內的元素構成的二叉樹獲得的最大收益。

[l,r]kf[l][r]=max(f[l][k1]×f[k+1][r]+w[k]k[l,r]狀態計算:\\區間[l,r],根節點爲k:f[l][r]=max(f[l][k-1]×f[k+1][r]+w[k],k∈[l,r]。

g[l,r]kg[l][r]=k本題需要記錄具體方案,另開數組g存儲區間[l,r]的根節點k,即g[l][r]=k。

注意:

(k=lk=r)1當根節點爲區間端點時(k=l或k=r),僅存在一顆子樹,此時將另一顆子樹賦值爲1再計算。

>>另外,前序遍歷可以採用遞歸輸出。順序爲根->左->右。

代碼:

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int N=35;

int n,w[N],f[N][N],g[N][N];

void pre(int l,int r)
{
    if(l>r) return ;
    int root = g[l][r];
    cout<<root<<' ';
    pre(l,root-1);
    pre(root+1,r);
    
}

int main()
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>w[i];
    
    for(int len=1;len<=n;len++)
        for(int l=1;l+len-1<=n;l++)
        {
            int r=l+len-1;
            if(len==1)
            {
                f[l][r]=w[l];
                g[l][r]=l;
            }
            else
            {
                for(int k=l;k<=r;k++)
                {
                    int left = k==l ? 1 : f[l][k-1];
                    int right = k==r ? 1 : f[k+1][r];
                    int score=left*right+w[k];
                    if(f[l][r]<score)
                    {
                        f[l][r]=score;
                        g[l][r]=k;
                    }
                }
            }
        }
        
    cout<<f[1][n]<<endl;
    pre(1,n);
    
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章