479. 加分二叉樹
阿新 • • 發佈:2022-03-15
題目連結
479. 加分二叉樹
設一個 \(n\) 個節點的二叉樹 tree 的中序遍歷為\((1,2,3,…,n)\),其中數字 \(1,2,3,…,n\) 為節點編號。
每個節點都有一個分數(均為正整數),記第 \(i\) 個節點的分數為 \(d_i\),tree 及它的每個子樹都有一個加分,任一棵子樹 subtree(也包含 tree 本身)的加分計算方法如下:
subtree的左子樹的加分 × subtree的右子樹的加分 + subtree的根的分數
若某個子樹為空,規定其加分為 \(1\)。
葉子的加分就是葉節點本身的分數,不考慮它的空子樹。
試求一棵符合中序遍歷為\((1,2,3,…,n)\)
要求輸出:
(1)tree的最高加分
(2)tree的前序遍歷
輸入格式
第 \(1\) 行:一個整數 \(n\),為節點個數。
第 \(2\) 行:\(n\) 個用空格隔開的整數,為每個節點的分數(0<分數<100)。
輸出格式
第 \(1\) 行:一個整數,為最高加分(結果不會超過int範圍)。
第 \(2\) 行:\(n\) 個用空格隔開的整數,為該樹的前序遍歷。如果存在多種方案,則輸出字典序最小的方案。
資料範圍
\(n<30\)
輸入樣例:
5
5 7 1 2 10
輸出樣例:
145
3 1 2 4 5
解題思路
區間dp
-
狀態表示:\(f[l][r]\)
-
狀態計算:\(f[l][r]=max(f[l][r],f[l][k-1]*f[k+1][r]+w[k]\),其中 \(k\) 為該區間組成的樹
帶著區間和權值反著推即可得整棵樹的結構
- 時間複雜度:\(O(n^2)\)
程式碼
// Problem: 加分二叉樹 // Contest: AcWing // URL: https://www.acwing.com/problem/content/description/481/ // Memory Limit: 128 MB // Time Limit: 1000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> //#define int long long #define help {cin.tie(NULL); cout.tie(NULL);} #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef pair<LL, LL> PLL; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } const int N=35; int n,w[N],f[N][N]; void dfs(int x,int l,int r) { for(int i=l;i<=r;i++) if(i==l) { if(x==f[i+1][r]+w[i]) { cout<<i<<' '; dfs(f[i+1][r],i+1,r); return ; } } else if(i==r) { if(x==f[l][i-1]+w[i]) { cout<<i<<' '; dfs(f[l][i-1],l,i-1); return ; } } else if(x==f[l][i-1]*f[i+1][r]+w[i]) { cout<<i<<' '; dfs(f[l][i-1],l,i-1); dfs(f[i+1][r],i+1,r); return ; } } int main() { cin>>n; for(int i=1;i<=n;i++)cin>>w[i]; for(int i=1;i<=n;i++)f[i][i]=w[i]; for(int len=2;len<=n;len++) for(int l=1;l+len-1<=n;l++) { int r=l+len-1; for(int k=l;k<=r;k++) { if(k==l) f[l][r]=max(f[l][r],f[k+1][r]+w[k]); else if(k==r) f[l][r]=max(f[l][r],f[l][k-1]+w[k]); else f[l][r]=max(f[l][r],f[l][k-1]*f[k+1][r]+w[k]); } } cout<<f[1][n]<<'\n'; dfs(f[1][n],1,n); return 0; }