1. 程式人生 > >NOIp2003 加分二叉樹

NOIp2003 加分二叉樹

輸出 我們 .org tdi gist getch www ++i digi

Luogu

題目告訴了我們中序遍歷為 \((1,2,...,n)\),所以每一棵子樹的根都會將這個區間一分為三。那麽設 \(dp[l][r]\) 為將 \((l,l+1,l+2,...,r)\) 是中序遍歷的子樹的加分。那麽轉移的時候枚舉一下根,也就是斷點。每次轉移的時候保存下根,方案遞歸輸出。

\[dp[l,r]=\max_{l≤k≤r} \{dp[l,k-1]*dp[k+1,r]+A_k \}\]

#include <iostream>
#include <cstdio>

const int max_n = 30 + 5;

int N;
int Dp[max_n][max_n], Root[max_n][max_n];

inline
int read() { register int x = 0; register char ch = getchar(); while(!isdigit(ch)) ch = getchar(); while(isdigit(ch)) { x = (x << 1) + (x << 3) + ch - ‘0‘; ch = getchar(); } return x; } void out(int l, int r) { printf("%d ", Root[l][r]); if
(l == r) return; else if(Root[l][r] == l) out(Root[l][r] + 1, r); else if(Root[l][r] == r) out(l, Root[l][r] - 1); else { out(l, Root[l][r] - 1); out(Root[l][r] + 1, r); } } int main() { N = read(); for(int i = 1; i <= N; ++i) { Dp[i][i] = read(); Root[i][i] = i; } for
(int len = 2; len <= N; ++len) { for(int l = 1; l <= N - len + 1; ++l) { int r = l + len - 1; for(int k = l; k <= r; ++k) { int t = ((Dp[l][k - 1]) ? Dp[l][k - 1] : 1) * ((Dp[k + 1][r]) ? Dp[k + 1][r] : 1) + Dp[k][k]; if(Dp[l][r] < t) { Dp[l][r] = t; Root[l][r] = k; } } } } printf("%d\n", Dp[1][N]); out(1, N); return 0; }

NOIp2003 加分二叉樹