479. 加分二叉树

题目链接

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)\)且加分最高的二叉树 tree。

要求输出:

(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]\) 表示中序遍历中区间 \([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;
}
posted @ 2022-03-15 21:26  zyy2001  阅读(249)  评论(0编辑  收藏  举报