時間限制: 1 sec 記憶體限制: 125 mb
提交: 11 解決: 7
設乙個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的前序遍歷
第1行:乙個整數n(n<30),為節點個數。
第2行:n個用空格隔開的整數,為每個節點的分數(分數<100)。
第1行:乙個整數,為最高加分(結果不會超過4,000,000,000)。
第2行:n個用空格隔開的整數,為該樹的前序遍歷。
55 7 1 2 10
1453 1 2 4 5
提高組-2023年noip
題目型別:
樹形dp
思路:首先,我們要做的就是設計狀態,其實就是設計dp陣列的含義,它要滿足無後效性。關注這個 左子樹*右子樹+根 我只要知道左子樹分數和右子樹分數和根的分數(已給出),不就可以了嗎?管他子樹長什麼樣!
所以,我們f陣列存的就是最大分數,怎麼存呢?
我們發現:子樹是乙個或多個節點的集合。
那麼我們可不可以開乙個f[i][j],f[i][j]來表示節點i到節點j成樹的最大加分呢?可以先保留這個想法(畢竟暫時也想不到更好的了)。
如果這樣話,我們就來設計狀態轉移方程。按照剛剛的設計來說的話,我們的答案就是f[1][n]了,那麼我們可以從小的子樹開始,也就是len,區間長度。有了區間長度我們就要列舉區間起點,i為區間起點,然後就可以算出區間終點j。通過加分二叉樹的式子我們可以知道,二叉樹的分取決於誰是根,於是我們就在區間內列舉根k。
特別的,f[i][i]=a[i]f[i][i]=a[i],其中a[i]為第i個節點的分數。
因為是要求最大值,所以我們就可以設計出f[i][j]=max(f[i][k-1]*f[k+1][j]+f[k][k])f[i][j]=max(f[i][k−1]*f[k+1][j]+f[k][k])於是乎,我們就自己設計出了乙個dp過程,因為是順著來的,所以很少有不成立的。
至於輸出前序遍歷,我們再設計乙個狀態root[i][j]來表示節點i到節點j成樹的最大加分所選的根節點。所以我們按照$根->左->右$的順序遞迴輸出即可。
#includeusingnamespace
std;
const
int maxn = 50
;typedef
long
long
ll;ll n;
//f[i][j]表示i到j子樹的最大分數
ll f[maxn][maxn],root[maxn][maxn];
void
print(ll l, ll r)
intmain()
for(int len=1;len//
以子樹的長度遍歷,1個節點的子樹,2個節點的子樹。。。
if(f[k+1][j]==0
)
if(f[i][j]}}}
cout
<1][n]
1, n);
return0;
}
posted on 2019-04-26 23:19
收藏時間限制: 1 sec 記憶體限制: 125 mb
提交: 11 解決: 7
設乙個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的前序遍歷
第1行:乙個整數n(n<30),為節點個數。
第2行:n個用空格隔開的整數,為每個節點的分數(分數<100)。
第1行:乙個整數,為最高加分(結果不會超過4,000,000,000)。
第2行:n個用空格隔開的整數,為該樹的前序遍歷。
55 7 1 2 10
1453 1 2 4 5
提高組-2023年noip
題目型別:
樹形dp
思路:首先,我們要做的就是設計狀態,其實就是設計dp陣列的含義,它要滿足無後效性。關注這個 左子樹*右子樹+根 我只要知道左子樹分數和右子樹分數和根的分數(已給出),不就可以了嗎?管他子樹長什麼樣!
所以,我們f陣列存的就是最大分數,怎麼存呢?
我們發現:子樹是乙個或多個節點的集合。
那麼我們可不可以開乙個f[i][j],f[i][j]來表示節點i到節點j成樹的最大加分呢?可以先保留這個想法(畢竟暫時也想不到更好的了)。
如果這樣話,我們就來設計狀態轉移方程。按照剛剛的設計來說的話,我們的答案就是f[1][n]了,那麼我們可以從小的子樹開始,也就是len,區間長度。有了區間長度我們就要列舉區間起點,i為區間起點,然後就可以算出區間終點j。通過加分二叉樹的式子我們可以知道,二叉樹的分取決於誰是根,於是我們就在區間內列舉根k。
特別的,f[i][i]=a[i]f[i][i]=a[i],其中a[i]為第i個節點的分數。
因為是要求最大值,所以我們就可以設計出f[i][j]=max(f[i][k-1]*f[k+1][j]+f[k][k])f[i][j]=max(f[i][k−1]*f[k+1][j]+f[k][k])於是乎,我們就自己設計出了乙個dp過程,因為是順著來的,所以很少有不成立的。
至於輸出前序遍歷,我們再設計乙個狀態root[i][j]來表示節點i到節點j成樹的最大加分所選的根節點。所以我們按照$根->左->右$的順序遞迴輸出即可。
#includeusingnamespace
std;
const
int maxn = 50
;typedef
long
long
ll;ll n;
//f[i][j]表示i到j子樹的最大分數
ll f[maxn][maxn],root[maxn][maxn];
void
print(ll l, ll r)
intmain()
for(int len=1;len//
以子樹的長度遍歷,1個節點的子樹,2個節點的子樹。。。
if(f[k+1][j]==0
)
if(f[i][j]}}}
cout
<1][n]
1, n);
return0;
}
洛谷 P1040 加分二叉樹
題目描述 設乙個n個節點的二叉樹tree的中序遍歷為 1,2,3,n 其中數字1,2,3,n為節點編號。每個節點都有乙個分數 均為正整數 記第i個節點的分數為di,tree及它的每個子樹都有乙個加分,任一棵子樹subtree 也包含tree本身 的加分計算方法如下 subtree的左子樹的加分 su...
洛谷 P1040 加分二叉樹
題目描述 設乙個n個節點的二叉樹tree的中序遍歷為 1,2,3,n 其中數字1,2,3,n為節點編號。每個節點都有乙個分數 均為正整數 記第i個節點的分數為di,tree及它的每個子樹都有乙個加分,任一棵子樹subtree 也包含tree本身 的加分計算方法如下 subtree的左子樹的加分 su...
洛谷P1040 加分二叉樹
設乙個 n 個節點的二叉樹tree的中序遍歷為 1,2,3,n 其中數字 1,2,3,n 為節點編號。每個節點都有乙個分數 均為正整數 記第 i 個節點的分數為 di,tree 及它的每個子樹都有乙個加分,任一棵子樹 subtree 也包含 tree 本身 的加分計算方法如下 subtree 的左子...