week12-D-正则括号

题意
We give the following inductive definition of a “regular brackets” sequence:

the empty sequence is a regular brackets sequence,
if s is a regular brackets sequence, then (s) and [s] are regular brackets sequences, and
if a and b are regular brackets sequences, then ab is a regular brackets sequence.
no other sequence is a regular brackets sequence
For instance, all of the following character sequences are regular brackets sequences:

(), [], (()), ()[], ()[()]

while the following character sequences are not:

(, ], )(, ([)], ([(]

Given a brackets sequence of characters a1a2 … an, your goal is to find the length of the longest regular brackets sequence that is a subsequence of s. That is, you wish to find the largest m such that for indices i1, i2, …, im where 1 ≤ i1 < i2 < … < im ≤ n, ai1ai2 … aim is a regular brackets sequence.

Given the initial sequence ([([]])], the longest regular brackets subsequence is [([])].

Input
The input test file will contain multiple test cases. Each input test case consists of a single line containing only the characters (, ), [, and ]; each input test will have length between 1 and 100, inclusive. The end-of-file is marked by a line containing the word “end” and should not be processed.

output:

For each input case, the program should print the length of the longest possible regular brackets subsequence on a single line.

sample input:

((()))
()()()
([]])
)[)(
([][][)
end

sample output

6
6
4
0
6

 思路:

题目给出了关于一个正则括号序列的定义,要我们在序列中找到一个最长子序列,使得其中包含的正则序列最长(可以理解为括号对数最多)。

1. 状态转移方程

根据题意可知,假设我们扫描一个区间[i,j],其中i和j分别为元素的下标,

区间内的正则括号数量总数为ai~aj中一对括号am和am’的个数
若将区间分为两个子区间:[i,k] 和 [k+1,j] —— 两个区间中分别含有k和z个正则括号数量。
显然,这两个区间的正则括号数量之和同样也属于区间[i,j]所包含的正则括号数量。但是,两个子区间相加所得的正则括号总数不一定等于以大区间为标准计算所得正则括号的数量。
例如:
假设原序列为—— [()][)]] , 则其所包含的最长正则子序列为[()];若将其分为 [()]和[)]] ,两个区间中分别包含的最大子序列为 [()] 和 [] 。
显然,两个子区间的正则括号数量之和不等于且大于原区间的正则序括号数量。
而区间[i,j]可以被分为j - i + 1对子区间。因此,区间[i,j]所包含的正则括号最大值应为该区间的正则括号数量和这j - i + 1对子区间正则括号数量和之中的最大值。

所以,另令ans[i][j]为区间[i,j]的最大正则括号数量,则状态转移方式为:

ans[i][j] = max(ans[i][j],ans[i][k] + ans[k + 1][j]);

2. 如何求区间[i,j]的正则括号数量?

状态转移方程确定后,问题就在于如何确定区间[i,j]的正则括

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <string>
 4 using namespace std;
 5 
 6 int ans[101][101];
 7 
 8 int main()
 9 {
10     
11     string s;
12     
13     while( cin>>s && s!="end" )
14     {
15         memset(ans,0,sizeof(ans));
16         
17         for ( int i = s.size() - 1 ; i >= 0 ; i-- )
18         {
19             for ( int j = i + 1 ; j < s.size() ; j++ )
20             {
21                 //算入(s) / [s]的情况
22                 if((s[i] == '(' && s[j] == ')') || (s[i] == '[' && s[j] == ']'))
23                     ans[i][j] = ans[i + 1][j - 1] + 2;
24                 
25                 //将[i,j]分为j - i + 1对子区间
26                 //判断[i,j]中的两个子区间的长度和是否更大,更大就更新
27                 //其实更新的就是这段区间中满足()[]这样情况的两个子区间
28                 for ( int k = i ; k <= j ; k++ )
29                     ans[i][j] = max(ans[i][j],ans[i][k] + ans[k + 1][j]);
30             }
31         }
32          cout<<ans[0][s.size()-1]<<endl;
33     }
34       
35     return 0;
36 }
37 
38 
39     
40     
41     
42     
43     
44     
45     

号数量ans[i][j]。

显然,当第i个和第j个为相同括号时,就代表着区间[i,j]的正则括号数量是在区间[i - 1,j - 1]的正则括号基础上增加了两个;反之,则说明区间[i,j]与区间[i - 1,j - 1]的正则括号数量相同,并无改变。

代码:

原文地址:https://www.cnblogs.com/liuzhuan-xingyun/p/13053713.html