AcWing 479. 加分二叉树(区间dp)
程序员文章站
2022-07-12 21:57:40
...
设一个n个节点的二叉树tree的中序遍历为(1,2,3,…,n),其中数字1,2,3,…,n为节点编号。
每个节点都有一个分数(均为正整数),记第i个节点的分数为di,tree及它的每个子树都有一个加分,任一棵子树subtree(也包含tree本身)的加分计算方法如下:
subtree的左子树的加分 × subtree的右子树的加分 + subtree的根的分数
若某个子树为空,规定其加分为1。叶子的加分就是叶节点本身的分数,不考虑它的空子树。
试求一棵符合中序遍历为(1,2,3,…,n)且加分最高的二叉树tree。
要求输出:
(1)tree的最高加分
(2)tree的前序遍历
输入格式
第1行:一个整数n,为节点个数。
第2行:n个用空格隔开的整数,为每个节点的分数(0<分数<100)。
输出格式
第1行:一个整数,为最高加分(结果不会超过4,000,000,000)。
第2行:n个用空格隔开的整数,为该树的前序遍历。如果存在多种方案,则输出字典序最小的方案。
数据范围
n<30
输入样例:
5
5 7 1 2 10
输出样例:
145
3 1 2 4 5
思路:
区间DP同样适用于二叉树:
枚举二叉树的节点个数 len, 枚举二叉树的组成区间(l, r), 枚举根节点 k, 从而得到状态转移方程式:
f[ l ] [ r ] = max(f[ l ] [ r ], f[ l ] [ k - 1] + f[ l ] [k + 1], + w[k])
更新最大值的同时, 记录每一个树的根节点
答案:
#include <iostream>
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define INF 0x3f3f3f3f3f3f3f3f
#define PII pair<int,int>
#define PLL pair<ll,ll>
#define pb push_back
#define eps 1e-6
const int mod = 1e9 + 7;
const int N = 1e5 + 10;
const int M = 35;
using namespace std;
int n;
ll dp[M];
ll mp[M][M];
ll vp[M][M];
void DFS(int l,int r){
if(l>r) return ;
int root=vp[l][r];
cout<<root<<" ";
DFS(l,root-1);
DFS(root+1,r);
}
void solve(){;
cin>>n;
for(int i=1;i<=n;i++){
cin>>dp[i];
}
for(int i=1;i<=n;i++){
mp[i][i]=dp[i];
vp[i][i]=i;
}
for(int i=2;i<=n;i++){
for(int j=1;i+j-1<=n;j++){
int key=i+j-1;
for(int k=j;k<=key;k++){
int l=(j==k?1:mp[j][k-1]);
int r=(key==k?1:mp[k+1][key]);
int res=l*r+dp[k];
if(res>mp[j][key]){
mp[j][key]=res;
vp[j][key]=k;
}
}
}
}
cout<<mp[1][n]<<endl;
DFS(1,n);
cout<<endl;
}
int main()
{
solve();
return 0;
}
上一篇: 【Vue高级】MVVM实现原理(六)—— 双向数据绑定的实现
下一篇: 各种协议与HTTP协议的关系