列表

详情


NC50511. 加分二叉树

描述

设一个n个节点的二叉树的中序遍历为,其中数字为节点编号。每个节点都有一个分数(均为正整数),记第i个节点的分数为d_i及它的每个子树都有一个加分,任一棵子树(也包含本身)的加分计算方法如下:
的左子树加分为l,右子树加分为r,的根的分数为a,则的加分为:

若某个子树为空,规定其加分为1,叶子的加分就是叶节点本身的分数。不考虑它的空子树。
试求一棵符合中序遍历为且加分最高的二叉树
要求输出:
的最高加分;的前序遍历。输入格式
  1. 第一行一个整数n表示节点个数;
  2. 第二行n个空格隔开的整数,表示各节点的分数。

输入描述

第一行一个整数n,表示节点个数;
第二行n个用空格隔开的整数,表示di。

输出描述

第一行一个整数,为最高加分b;
第二行n个用空格隔开的整数,为该树的前序遍历。

示例1

输入:

5
5 7 1 2 10

输出:

145
3 1 2 4 5

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 4ms, 内存消耗: 376K, 提交时间: 2019-10-24 13:36:30

#include<cstring>
#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
int dp[100][100];
int root[100][100];
int find(int l, int r) {
	ll now, ans;
	if (l > r) return 1;
	if (dp[l][r] == -1) {
		for (int i = l; i <= r; i++) {
			now = find(l, i - 1)*find(i + 1, r) + dp[i][i];
			if (now > dp[l][r]) {
				dp[l][r] = now;
				root[l][r] = i;
			}
		}
	}
	return dp[l][r];
}
int flag = 1;
int println(int l,int r) {
	if (l > r) return 0;
	if (flag) flag = 0;
	else printf(" ");
	printf("%d", root[l][r]);

	println(l, root[l][r] - 1);
	println(root[l][r] + 1, r);
}
int main() {
	int n;
	scanf("%d", &n);
	memset(dp, -1, sizeof(dp));
	for (int i = 1; i <= n; i++) {
		scanf("%d", &dp[i][i]);
		root[i][i] = i;
	}
	printf("%d\n", find(1, n));
	
	println(1, n);
	return 0;
}

C++ 解法, 执行用时: 3ms, 内存消耗: 584K, 提交时间: 2022-06-08 11:22:25

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll d[1111][1111];
ll f[1111][1111];
ll a[1111],n;
void dfs(ll l,ll r)
{
	if(l>r)return ;
	cout<<d[l][r]<<" ";
	dfs(l,d[l][r]-1);
	dfs(d[l][r]+1,r);
}
int main()
{
	scanf("%d",&n);
	for(ll i=1; i<=n; i++)
	{
		scanf("%d",&a[i]);
		f[i][i]=a[i];
		d[i][i]=i;
	}
	for(ll len=1; len<n; len++)
	for(ll i=1; i+len<=n; i++)
	{
		int j=i+len;
		for(ll k=i; k<=j; k++)
		{
			int l=f[i][k-1];
			int r=f[k+1][j];
			if(k==i)l=1;
			if(k==j)r=1;
			if(l*r+a[k]>f[i][j])
			{
				f[i][j]=l*r+a[k];
				d[i][j]=k;
			}
		}
	}
	cout<<f[1][n]<<endl;
	dfs(1,n);
	cout<<endl;
    return 0;
}

上一题