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: }