1. 程式人生 > >洛谷P2308 新增括號

洛谷P2308 新增括號

洛谷P2308 新增括號

題目背景:

  給定一個正整數序列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箇中間和,求出使中間和之和最小的添括號方法。

思路:

  區間dp

  f[i][j]表示區間[i,j]和並後的最小和

  然後因為這題還有一個毒瘤輸出

  所以還要有一個附加陣列pos,記k=pos[i][j],pos[i][j]表示區間[i,j]合併時是由[l,k]和[k+1,j]兩個區間合併的,然後用一個遞迴就可以輸出結果。

CODE:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 using namespace std;
 6
#define MAXN 1010 7 int nums[MAXN],sum[MAXN]; 8 int f[MAXN][MAXN],pos[MAXN][MAXN]; 9 int i,j,k,m,n,ans; 10 void print(int l,int r){ 11 if(l==r){ 12 printf("%d",nums[l]); 13 return; 14 } 15 int mid=pos[l][r]; 16 putchar('('); 17 print(l,mid); 18 putchar('+');
19 print(mid+1,r); 20 putchar(')'); 21 } 22 void print2(int l,int r){ 23 if(l==r) return; 24 int mid=pos[l][r]; 25 print2(l,mid); 26 print2(mid+1,r); 27 printf("%d ",sum[r]-sum[l-1]); 28 } 29 int main(){ 30 scanf("%d",&n); 31 for(i=1;i<=n;i++){ 32 scanf("%d",nums+i); 33 nums[n+i]=nums[i]; 34 } 35 sum[0]=0; 36 for(i=1;i<=n;i++) sum[i]=sum[i-1]+nums[i]; 37 for(i=2;i<=n;i++){ 38 for(j=1;j<=n-i+1;j++){ 39 int t=i+j-1; 40 f[j][t]=1000000000; 41 for(k=j;k<=t-1;k++){ 42 if(f[j][t]>=f[j][k]+f[k+1][t]){ 43 f[j][t]=f[j][k]+f[k+1][t]; 44 pos[j][t]=k; 45 } 46 } 47 f[j][t]+=sum[t]-sum[j-1]; 48 } 49 } 50 ans=f[1][n]; 51 print(1,n); printf("\n"); 52 printf("%d\n",ans); 53 print2(1,n); printf("\n"); 54 return 0; 55 }