添加括号(区间dp+求方案)

添加括号

题目背景

给定一个正整数序列a(1),a(2),…,a(n),(1<=n<=20)

不改变序列中每个元素在序列中的位置,把它们相加,并用括号记每次加法所得的和,称为中间和。

例如:

给出序列是4,1,2,3。

第一种添括号方法:

((4+1)+(2+3))=((5)+(5))=(10)

有三个中间和是5,5,10,它们之和为:5+5+10=20

第二种添括号方法

(4+((1+2)+3))=(4+((3)+3))=(4+(6))=(10)

中间和是3,6,10,它们之和为19。

题目描述

现在要添上n-1对括号,加法运算依括号顺序进行,得到n-1个中间和,求出使中间和之和最小的添括号方法。

输入格式

共两行。 第一行,为整数n。(1< =n< =20) 第二行,为a(1),a(2),…,a(n)这n个正整数,每个数字不超过100。

输出格式

输出3行。 第一行,为添加括号的方法。 第二行,为最终的中间和之和。 第三行,为n-1个中间和,按照从里到外,从左到右的顺序输出。

样例 #1

样例输入 #1

4
4 1 2 3

样例输出 #1

(4+((1+2)+3))
19
3 6 10

提示

范围在题目上有说明。

思路

这道题的第二小问你不觉得很熟悉吗,它不就是合并果子的板子小题吗?因此我们这道题用区间dp来做,只不过这道题相比那道题多了求方案。对于这样的,我们可以类似二叉树的中序遍历那样来找方案。

具体怎么找方案:

  • 我们可以在区间dp开始枚举断点的时候,如果状态已经更新了,我们就可以记录此时状态的断点。
  • 然后我们采取中序遍历的板子来写出答案。

代码

//这道题如果不求方案的话就是石子合并了
//所以,这道题就是很经典的区间合并,只不过要求方案
//对于题目的第一第三问,我们可以利用树的方式遍历(也就是中序遍历)

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

const int N = 25;

int f[N][N];
int n;
int w[N];
int s[N];//前缀和
int pre[N][N];
int ans[N],cnt;

void print(int x,int y){
    if(x==y){
        cout<<s[x]-s[x-1];
        return;
    }
    
    cout<<"(";
    print(x,pre[x][y]);
    cout<<"+";
    print(pre[x][y]+1,y);
    cout<<")";
    ans[++cnt]=s[y]-s[x-1];
}

int main(){
    cin>>n;
    
    memset(f,0x3f,sizeof f);
    
    for(int i=1;i<=n;i++){
        cin>>w[i];
        s[i]=s[i-1]+w[i];
        f[i][i]=0;
    }
    
    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++){//为什么不能等于r,因为必须要有两份
                // f[l][r]=min(f[l][r],f[l][k]+f[k+1][r]+s[r]-s[l-1]);
                if(f[l][k]+f[k+1][r]+s[r]-s[l-1]<f[l][r]){
                    f[l][r]=f[l][k]+f[k+1][r]+s[r]-s[l-1];
                    pre[l][r]=k;//记录分界点
                }
            }
        }
    }
    print(1,n);//中序遍历
    cout<<endl;
    cout<<f[1][n]<<endl;
    for(int i=1;i<=cnt;i++){
        cout<<ans[i]<<' ';
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

green qwq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值