• 【原】 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: }

    如果您满意我的博客,请点击“订阅Allen Sun的技术博客”即可订阅,谢谢:)

    原创文章属于Allen Sun
    欢迎转载,但请注明文章作者Allen Sun和链接
  • 相关阅读:
    nginx设置开机自启
    sublimeText3和phpstrom使用
    快捷键整理
    nginx日志分割及备份
    nginx日志设置
    nginx上部署PHP
    C语言三种参数传递方式
    浮点数在内存中的存储方式
    windows下git安装过程
    偏移二进制编码和二进制补码的区别
  • 原文地址:https://www.cnblogs.com/allensun/p/1869417.html
Copyright © 2020-2023  润新知