luogu1040 加分二叉樹
阿新 • • 發佈:2018-09-15
遍歷 整數 esp oid class nod val rgs str
題目大意
設一個n個節點的二叉樹tree的中序遍歷為(l,2,3,…,n),其中數字1,2,3,…,n為節點編號。每個節點都有一個分數(均為正整數),記第j個節點的分數為di,tree及它的每個子樹都有一個加分,任一棵子樹subtree(也包含tree本身)的加分計算方法如下:
subtree的左子樹的加分× subtree的右子樹的加分+subtree的根的分數
若某個子樹為主,規定其加分為1,葉子的加分就是葉節點本身的分數。不考慮它的空子樹。
試求一棵符合中序遍歷為(1,2,3,…,n)且加分最高的二叉樹tree。要求輸出;
(1)tree的最高加分
(2)tree的前序遍歷
題解
本題最容易忽略的性質便是二叉樹中的每一個子樹的中序遍歷都是一段連續的區間。所以對於一段區間,根據選區間中哪個點作為根來分類動規即可。
#include <cstdio> #include <cstring> #include <algorithm> #include <cstdarg> using namespace std; void _printf(char *format, ...) { #ifdef _DEBUG va_list(args); va_start(args, format); vprintf(format, args); va_end(args); #endif } //------------------------------------------------------------------------- const int MAX_NODE = 35; long long F[MAX_NODE][MAX_NODE]; int RootId[MAX_NODE][MAX_NODE], Val[MAX_NODE]; int TotNode; void DP() { for (int i = 1; i <= TotNode; i++) F[i][i - 1] = F[i][i + 1] = 1; for (int i = 1; i <= TotNode; i++) { F[i][i] = Val[i]; RootId[i][i] = i; } for (int len = 2; len <= TotNode; len++) for (int i = 1; i <= TotNode - len + 1; i++) { int j = i + len - 1; for (int k = i; k <= j; k++) { if (F[i][k - 1] * F[k + 1][j] + Val[k] > F[i][j]) { F[i][j] = F[i][k - 1] * F[k + 1][j] + Val[k]; RootId[i][j] = k; } } } } void Print(int l, int r) { if (l > r) return; printf("%d ", RootId[l][r]); Print(l, RootId[l][r] - 1); Print(RootId[l][r] + 1, r); } int main() { #ifdef _DEBUG freopen("c:\\noi\\source\\input.txt", "r", stdin); #endif scanf("%d", &TotNode); for (int i = 1; i <= TotNode; i++) scanf("%d", Val + i); DP(); printf("%lld\n", F[1][TotNode]); Print(1, TotNode); return 0; }
luogu1040 加分二叉樹