NOIp2003 加分二叉樹
阿新 • • 發佈:2018-02-26
輸出 我們 .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 加分二叉樹