zoukankan      html  css  js  c++  java
  • 【原】 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和链接
  • 相关阅读:
    形象理解ERP(转)
    禁用windows server 2008 域密码复杂性要求策略
    How to adding find,filter,remove filter on display method Form
    Windows Server 2008 R2激活工具
    How to using bat command running VS development SSRS report
    Creating Your First Mac AppGetting Started
    Creating Your First Mac AppAdding a Track Object 添加一个 Track 对象
    Creating Your First Mac AppImplementing Action Methods 实现动作方法
    Creating Your First Mac AppReviewing the Code 审查代码
    Creating Your First Mac AppConfiguring the window 设置窗口
  • 原文地址:https://www.cnblogs.com/allensun/p/1869417.html
Copyright © 2011-2022 走看看