AcWing 区间DP相关问题 479. 加分二叉树

N = int(input())
arr = list(map(int, input().split()))

from functools import lru_cache


# dp(i, j) 表示所有中序序列是arr[i:j+1]的二叉树的价值的最大值以及最大值对应的树的根节点
# 为了让前序序列的字典序最小,价值一样大情况下,根节点选更靠前的
@lru_cache(typed=False, maxsize=128000000)
def dp(i, j):
    if j == i:
        return arr[i], i

    max_val = -1
    root = -1
    for k in range(i, j + 1):
        if k == i:
            val = dp(i + 1, j)[0] + arr[i]
        elif k == j:
            val = dp(i, j - 1)[0] + arr[j]
        else:
            val = dp(i, k - 1)[0] * dp(k + 1, j)[0] + arr[k]

        if val > max_val:
            max_val, root = val, k

    return max_val, root


print(dp(0, N - 1)[0])

# 先序遍历打印二叉树, 因为最优划分已经全部算出来了,所以现在一个区间的最优划分方案就对应一个子树的根
arr = []


def dfs(i, j):
    if j < i:
        return

    if i == j:
        arr.append(str(j + 1))
        return

    root = dp(i, j)[1]
    arr.append(str(root + 1))
    dfs(i, root - 1)
    dfs(root + 1, j)


dfs(0, N - 1)
print(' '.join(arr))

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值