背景
给定一个正整数序列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
限制
各个测试点1s
来源
MaoLaoda

1 #include <iostream> 2 #include <algorithm> 3 #include <math.h> 4 #include <cstdio> 5 #include <stdlib.h> 6 #include <string.h> 7 8 using namespace std; 9 10 int num[30],f[30][30],h[30][30],sum[30][30],mid[100],step=0;//f[x][y]记录从x到y最小相加值,a=h[x][y]记录x到y最大值是由h[x][a]+h[a][y]得出的,mid记录中间数 11 int inf=999999; 12 13 int pri(int x,int y) 14 { 15 if(x==y) 16 { 17 printf("%d",num[x]); 18 return num[x]; 19 } 20 printf("("); 21 int n1=pri(x,h[x][y]); 22 printf("+"); 23 int n2=pri(h[x][y]+1,y); 24 printf(")"); 25 mid[++step]=n1+n2; 26 return mid[step]; 27 } 28 29 int main() 30 { 31 int n; 32 scanf("%d",&n); 33 for(int i=1;i<=n;i++) 34 { 35 scanf("%d",&num[i]); 36 sum[i][i]=num[i]; 37 } 38 for(int i=1;i<=n;i++) 39 for(int j=1;j<=n-i;j++) 40 sum[i][i+j]=sum[i][i+j-1]+num[i+j]; 41 for(int i=1;i<=n-1;i++) 42 for(int j=1;j<=n-i;j++) 43 { 44 f[j][j+i]=inf; 45 for(int k=j;k<=j+i;k++) 46 if(f[j][k]+f[k+1][j+i]+sum[j][j+i]<=f[j][j+i]) 47 { 48 f[j][j+i]=f[j][k]+f[k+1][j+i]+sum[j][j+i]; 49 h[j][j+i]=k; 50 } 51 } 52 pri(1,n); 53 printf(" "); 54 printf("%d ",f[1][n]); 55 printf("%d",mid[1]); 56 for(int i=2;i<=step;i++) 57 printf(" %d",mid[i]); 58 printf(" "); 59 return 0; 60 }
不算很难的题,主要思想还是非常规矩的dp(状态很好想)
但还是wa了两次,坑点在于要求括号提前
但我其实不是没看见这个要求,但我没有get到题主“子串越长,括号越多”的潜规则
现在想想稍微有道理一点了 不过括号提前这句话本身就有点……