【原】 POJ 1141 Brackets Sequence 动态规划 解题报告

 

http://poj.org/problem?id=1141

 

方法:
对角线方向求解DP。

设c[i][j]表示原串str[i...j]补齐后的最短长度。a[i][j]表示原串str[i...j]补齐后的字符串。
c[1][n]和a[1][n]即为所求结果。n为原串的长度。
 
初始状态:
c[i][i] = 2
a[i][i] = "()",if str[i]="(" or ")"
        = "[]",if str[i]="[" or "]"
c[i][j] = 0,if i>j

根据性质(3)一个序列如果是AB形式的话,我们可以划分为A,B两个子问题,我们可以得到递归式:
枚举[i,j)范围内的k
c[i][j] = min{ c[i][k] + c[k+1][j],for all k in [i,j) }
a[i][j] = a[i][k] + a[k+1][j]
此递归式为“最优二分检索树问题”形式:C[i,j]=w[i,j]+opt{C[i,k-1]+C[k,j]}.

根据性质(2)一个序列如果是[A]或者(A)的形式,我们可以把它降为向下分解为A即可
c[i][j] = min{ tmp , c[i+1][j-1]+2 } ,其中tmp就是由性质3得到的c[i][j]
a[i][j] = str[i] + c[i+1][j-1]+ str[j]

由上面可以看出c[N][N]矩阵的对角线都为2,左下部分全为0。
c[i][j]依赖于c[i][k]、c[k+1][j]和c[i+1][j-1]。所以需要以对角线为边界,沿对角线方向求解。

 

Description

Let us define a regular brackets sequence in the following way:
1. Empty sequence is a regular sequence.
2. If S is a regular sequence, then (S) and [S] are both regular sequences.
3. If A and B are regular sequences, then AB is a regular sequence.
For example, all of the following sequences of characters are regular brackets sequences:
(), [], (()), ([]), ()[], ()[()]
And all of the following character sequences are not:
(, [, ), )(, ([)], ([(]
Some sequence of characters '(', ')', '[', and ']' is given. You are to find the shortest possible regular brackets sequence, that contains the given character sequence as a subsequence. Here, a string a1 a2 ... an is called a subsequence of the string b1 b2 ... bm, if there exist such indices 1 = i1 < i2 < ... < in = m, that aj = bij for all 1 = j = n.

Input

The input file contains at most 100 brackets (characters '(', ')', '[' and ']') that are situated on a single line without any other characters among them.

Output

Write to the output file a single line that contains some regular brackets sequence that has the minimal possible length and contains the given sequence as a subsequence.

Sample Input

([(]

Sample Output

()[()]

 

   1: #include <stdio.h>
   2: #include <iostream>
   3: #include <string>
   4:  
   5: using namespace std ;
   6:  
   7: const int N = 101 ;
   8: const int INF = 0x7fffffff ;
   9:  
  10: int c[N][N] ;    //c[i][j]表示原串str[i...j]补齐后的最短长度
  11: string a[N][N] ; //a[i][j]表示原串str[i...j]补齐后的字符串
  12: char str[N] ;    //原串,从索引1开始
  13:  
  14: //返回原串长n
  15: int Initialize( )
  16: {
  17:     int i,j ;
  18:     int n ;
  19:  
  20:     scanf( "%s", (str+1) ) ;  //从索引1开始
  21:     n = strlen(str+1) ;
  22:  
  23:     memset( c , 0 , sizeof(c) ) ;
  24:     
  25:     for( i=1 ; i<=n ; ++i )  //设置对角线初始值
  26:     {
  27:         for( j=1 ; j<=n ; ++j )
  28:             a[i][j] = "" ;
  29:         c[i][i] = 2 ;
  30:         if( str[i]=='(' || str[i]==')' )
  31:             a[i][i] = "()" ;
  32:         else
  33:             a[i][i] = "[]" ;
  34:     }
  35:  
  36:     return n ;
  37: }
  38:  
  39: inline
  40: bool Match( char a, char b )
  41: {
  42:     if( a=='(' && b==')' )
  43:         return true ;
  44:     else if( a=='[' && b==']' )
  45:         return true ;
  46:     else
  47:         return false ;
  48: }
  49:  
  50: void DP( int n )
  51: {
  52:     int i,j,k ;
  53:     int b,e ;
  54:  
  55:     //精妙的双循环使得按照对角线方向求解
  56:     for( j=1 ; j<n ; ++j )  //j为纵向比横向多出的距离
  57:     {
  58:         for( i=1 ; i+j<=n ; ++i )  //i+j即为纵向坐标
  59:         {
  60:             b = i ;
  61:             e = i+j ;
  62:             c[b][e] = INF ;
  63:  
  64:             for( k=b ; k<e ; ++k )  //性质3
  65:             {
  66:                 if( c[b][e] > c[b][k]+c[k+1][e] )
  67:                 {
  68:                     c[b][e] = c[b][k] + c[k+1][e] ;
  69:                     a[b][e] = a[b][k] + a[k+1][e] ;
  70:                 }
  71:             }
  72:  
  73:             if( Match( str[b] , str[e] ) )  //性质2
  74:             {
  75:                 if( c[b][e] > c[b+1][e-1]+2 )
  76:                 {
  77:                     c[b][e] = c[b+1][e-1]+2 ;
  78:                     a[b][e] = str[b] + a[b+1][e-1] + str[e] ;
  79:                 }
  80:             }
  81:         }
  82:     }
  83: }
  84:  
  85: void run1141()
  86: {
  87:     int n ;
  88:     n = Initialize() ;
  89:     DP(n) ;
  90:     cout<<a[1][n]<<endl ;
  91: }
posted @ 2010-11-04 21:43  Allen Sun  阅读(397)  评论(0编辑  收藏  举报