1. 程式人生 > >洛谷 P1040 加分二叉樹

洛谷 P1040 加分二叉樹

i++ nbsp radi 要求 names 輸入 技術分享 targe -o

      洛谷 P1040 加分二叉樹

題目描述

設一個 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 行: 1 個整數 n (n < 30) ,為節點個數。

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

輸出格式:

1 行: 1 個整數,為最高加分(Ans 4,000,000,000 )。

2 行: n 個用空格隔開的整數,為該樹的前序遍歷。

輸入輸出樣例

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

思路:用f[i][j]表示中序遍歷為 i 到 j 的一棵樹的最大加分
   則:f[i][j]=max{f[i][k]*f[k+1][j]+f[k][k],k為根節點}

   用d[i][j]記錄區間[i,j]的根節點, write(i,j)輸出區間[i,j]這棵樹
   則:write(i,j)==>wrie(i,d[i][j]-1)+d[i][j]+write(d[i][j]+1,j)

技術分享圖片
#include<cstdio>
#define M 55
using namespace std;

int n;
int f[M][M],d[M][M];

void write(int l, int r) {
    if(l > r) return;
    printf("%d ", d[l][r]);
    write(l, d[l][r]
-1); write(d[l][r]+1, r); } int main() { scanf("%d", &n); for(int i = 1; i <= n; i++) { scanf("%d", &f[i][i]); d[i][i] = i, f[i+1][i] = 1; } f[1][0] = 1; for(int k = 2; k <= n; k++) for(int s = 1; s+k-1 <= n; s++) for(int e = s+k-1,j = s; j <= e; j++) if(f[s][e] < f[s][j-1] * f[j+1][e] + f[j][j]) { f[s][e] = f[s][j-1] * f[j+1][e] + f[j][j]; d[s][e] = j; } printf("%d\n", f[1][n]); write(1, n); return 0; }
View Code


洛谷 P1040 加分二叉樹