P2308 添加括号

P2308 添加括号

题解

一看这题---我能AC

看完这题---我要换题

 

这题第二问其实就是一个链的石子合并,也就是不用处理环

所以一三问怎么处理???

数组 mid[ i ][ j ] 记录区间 [ l , r ] 的断点

数组 le[ i ] 表示 a[i] 左边有几个左括号

数组 ri[ i ] 表示 a[i] 右边有几个右括号

 

递归处理一下括号数

 

单数字两边肯定不能有括号

我们在区间左右各标记上左右括号之后,继续向下递归,分别处理断开的两段区间

 

递归处理括号数

 

 先输出数字周围的括号,再输出这个数字,注意每两个数字之间都是要有+连接的

 

然后输出最小合并

 

递归输出中间合并部分结果

 

合并左半部分的值,合并右半部分的值,两个部分一起合并的值

 

注意

 

(=的时候也是要更新一下mid的,可能是为了不断动态更新我编不动了

 

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<string>
#include<cstring>
#include<cstdlib>
#include<queue>

using namespace std;

typedef long long ll;

inline int read()
{
    int ans=0;
    char last=' ',ch=getchar();
    while(ch<'0'||ch>'9') last=ch,ch=getchar();
    while(ch>='0'&&ch<='9') ans=ans*10+ch-'0',ch=getchar();
    if(last=='-') ans=-ans;
    return ans;
}

int n,a[25],sum[25];
int f[25][25],mid[25][25];
int le[25],ri[25];

void cnt(int l,int r)
{
    if(l==r) return ;
    le[l]++;
    ri[r]++;
    cnt(l,mid[l][r]);
    cnt(mid[l][r]+1,r);
}

void print(int l,int r)
{
    if(l==r) return;
    print(l,mid[l][r]);
    print(mid[l][r]+1,r);
    printf("%d ",sum[r]-sum[l-1]);
}

int main()
{
    n=read();
    memset(f,0x7f,sizeof(f));
    for(int i=1;i<=n;i++) a[i]=read(),sum[i]=sum[i-1]+a[i],f[i][i]=0;
    
    for(int l=2;l<=n;l++)
      for(int i=1;i+l-1<=n;i++){
          int j=i+l-1;
          for(int k=i;k<j;k++){
              if(f[i][k]+f[k+1][j]<=f[i][j]){
                  f[i][j]=f[i][k]+f[k+1][j];
                  mid[i][j]=k;
              }
          }
        f[i][j]+=sum[j]-sum[i-1];
      }
    
    cnt(1,n);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=le[i];j++) printf("(");
        printf("%d",a[i]);
        for(int j=1;j<=ri[i];j++) printf(")");
        if(i!=n) printf("+");
    }
    printf("\n%d\n",f[1][n]);
    print(1,n);
    
    return 0;
}

 

posted @ 2019-11-22 17:41  晔子  阅读(174)  评论(0编辑  收藏  举报