設乙個n個節點的二叉樹tree的中序遍歷為(1,2,3,…,n),其中數字1,2,3,…,n為節點編號。
每個節點都有乙個分數(均為正整數),記第i個節點的分數為didi,tree及它的每個子樹都有乙個加分,任一棵子樹subtree(也包含tree本身)的加分計算方法如下:
subtree的左子樹的加分 × subtree的右子樹的加分 + subtree的根的分數
若某個子樹為空,規定其加分為1。葉子的加分就是葉節點本身的分數,不考慮它的空子樹。
試求一棵符合中序遍歷為(1,2,3,…,n)且加分最高的二叉樹tree。
要求輸出:
(1)tree的最高加分
(2)tree的前序遍歷
輸入格式
第1行:乙個整數n,為節點個數。
第2行:n個用空格隔開的整數,為每個節點的分數(0
《分數<
100)。
輸出格式
第1行:乙個整數,為最高加分(結果不會超過int範圍)。
第2行:n個用空格隔開的整數,為該樹的前序遍歷。如果存在多種方案,則輸出字典序最小的方案。
資料範圍
n<
30輸入樣例:55
71210
輸出樣例:
145312
45
區間dp,二叉樹的遍歷)
o(n3)
狀態表示:f[i]
[j] 表示中序遍歷是 w[i ~ j] 的所有二叉樹的得分的最大值。
狀態計算:f[i]
[j]=
max(f[i]
[k -1]
* f[k +1]
[j]+ w[k]
),即將f[i]
[j]表示的二叉樹集合按根節點分類,則根節點在 k 時的最大
得分即為 f[i]
[k -1]
* f[k +1]
[j]+ w[k],則f[i]
[j]即為遍歷
k 所取到的最大值。
在計算每個狀態的過程中,記錄每個區間的最大值所對應的根節點編號。
那麼最後就可以通過dfs求出最大加分二叉樹的前序遍歷了。
時間複雜度
狀態總數是 o
(n的2次方),計算每個狀態需要 o
(n) 的計算量,
因此總時間複雜度是 o
(n的3次方)。
#include
#include
#include
using
namespace std;
const
int n =30;
int n;
int w[n]
;int f[n]
[n], g[n]
[n];
void
dfs(
int l,
int r)
intmain()
}}} cout << f[1]
[n]<< endl;
dfs(
1, n)
;return0;
}
//記憶化搜尋
#include
#include
#include
using
namespace std;
const
int n =30;
int n;
int w[n]
;int f[n]
[n], g[n]
[n];
void
dfs2
(int l,
int r)
intdfs1
(int l,
int r)
}return v;
}int
main()
dfs1(1
, n)
;
cout << f[1]
[n]<< endl;
dfs2(1
, n)
;return0;
}
//記憶化搜尋,簡潔版
#include
#include
#include
using
namespace std;
const
int n =30;
int n;
int w[n]
;int f[n]
[n], g[n]
[n];
void
dfs2
(int l,
int r)
intdfs1
(int l,
int r)
for(
int k=l;k<=r;k++)}
return v;
}int
main()
區間DP 加分二叉樹
題目 設乙個n個節點的二叉樹tree的中序遍歷為 1,2,3,n 其中數字1,2,3,n為節點編號。每個節點都有乙個分數 均為正整數 記第i個節點的分數為 d i tree及它的每個子樹都有乙個加分,任一棵子樹subtree 也包含tree本身 的加分計算方法如下 subtree的左子樹的加分 su...
加分二叉樹(區間動規或記憶化搜尋)
設乙個n個節點的二叉樹tree的中序遍歷為 l,2,3,n 其中數字1,2,3,n為節點編號。每個節點都有乙個分數 均為正整數 記第i個節點的分數為di,tree及它的每個子樹都有乙個加分,任一棵子樹subtree 也包含tree本身 的加分計算方法如下 subtree的左子樹的加分 subtree...
加分二叉樹(遞迴,區間DP)
演算法 區間dp,二叉樹的遍歷 狀態表示 f i j 表示中序遍歷是 w i j 的所有二叉樹的得分的最大值。狀態計算 f i j max f i k 1 f k 1 j w k 即將 f i j 表示 的二叉樹集合按根節點分類,則根節點在 k 時的最大得分即 為 f i k 1 f k 1 j w...