POJ2955 Brackets —— 区间DP

题目链接:https://vjudge.net/problem/POJ-2955

 

Brackets
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 9630   Accepted: 5131

Description

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 i1i2, …, im where 1 ≤ i1 < i2 < … < im ≤ nai1ai2 … 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

Source

 

 

题解:

求最多有多少对括号匹配。典型的区间dp。

 

方法一:

1.如果区间[l,r]的两端匹配,则左右各缩进一格,从而转化成处理[l+1, r-1]的区间。

2.不管是否符合条件1,都尝试去枚举分割点,使得整个区间分成两半,这样就可以把大区间的处理转化成两个小区间的处理。

 

记忆化搜索:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <vector>
 6 #include <cmath>
 7 #include <queue>
 8 #include <stack>
 9 #include <map>
10 #include <string>
11 #include <set>
12 using namespace std;
13 typedef long long LL;
14 const int INF = 2e9;
15 const LL LNF = 9e18;
16 const int MOD = 1e9+7;
17 const int MAXN = 100+10;
18 
19 
20 char s[MAXN];
21 int dp[MAXN][MAXN];
22 
23 int dfs(int l, int r)
24 {
25     if(r<=l) return 0;
26     if(dp[l][r]!=-1) return dp[l][r];
27 
28     if( (s[l]=='('&&s[r]==')')||(s[l]=='['&&s[r]==']') )    //如果两端匹配,则可以缩减范围
29         dp[l][r] = dfs(l+1, r-1) + 1;
30     for(int k = l; k<r; k++)    //枚举分割点,分成两半
31         dp[l][r] = max(dp[l][r], dfs(l, k)+dfs(k+1, r));
32 
33     return dp[l][r];
34 }
35 
36 int main()
37 {
38     while(scanf("%s", s+1) && strcmp(s+1, "end"))
39     {
40         memset(dp, -1, sizeof(dp));
41         cout<< dfs(1, strlen(s+1))*2 <<endl;
42     }
43 }
View Code

递推:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <vector>
 6 #include <cmath>
 7 #include <queue>
 8 #include <stack>
 9 #include <map>
10 #include <string>
11 #include <set>
12 using namespace std;
13 typedef long long LL;
14 const int INF = 2e9;
15 const LL LNF = 9e18;
16 const int MOD = 1e9+7;
17 const int MAXN = 100+10;
18 
19 char s[MAXN];
20 int dp[MAXN][MAXN];
21 
22 int main()
23 {
24     while(scanf("%s", s+1) && strcmp(s+1, "end"))
25     {
26         memset(dp, 0, sizeof(dp));
27         int n = strlen(s+1);
28         for(int len = 2; len<=n; len++)
29         {
30             for(int l = 1; l<=n-len+1; l++)
31             {
32                 int r = l+len-1;
33                 if( (s[l]=='('&&s[r]==')') || (s[l]=='['&&s[r]==']') )
34                     dp[l][r] = dp[l+1][r-1] + 1;
35                 for(int k = l; k<r; k++)
36                     dp[l][r] = max(dp[l][r], dp[l][k]+dp[k+1][r]);
37             }
38         }
39         printf("%d\n", dp[1][n]*2);
40     }
41     return 0;
42 }
View Code

 

 

方法二:

1.可知一个符号最多只能与一个符号匹配,那么对于当前的符号,我们就枚举其他符号与其匹配(不管是能匹配成功)。

2.假设区间为 [l, r],为l枚举匹配符号,当枚举到k位置时,就把区间分割成了两部分:[l+1, k-1] 和 [k+1, r] 。从而就把大区间的求解转化为小区间的求解。

 

记忆化搜索:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <vector>
 6 #include <cmath>
 7 #include <queue>
 8 #include <stack>
 9 #include <map>
10 #include <string>
11 #include <set>
12 using namespace std;
13 typedef long long LL;
14 const int INF = 2e9;
15 const LL LNF = 9e18;
16 const int MOD = 1e9+7;
17 const int MAXN = 100+10;
18 
19 char s[MAXN];
20 int dp[MAXN][MAXN];
21 
22 int dfs(int l, int r)
23 {
24     if(r<=l) return 0;
25     if(dp[l][r]!=-1) return dp[l][r];
26 
27     dp[l][r] = dfs(l+1, r);
28     for(int k = l+1; k<=r; k++)
29     {
30         int ismatch = (s[l]=='('&&s[k]==')')||(s[l]=='['&&s[k]==']');
31         int tmp =  dfs(l+1, k-1)+dfs(k+1, r)+ismatch;
32         dp[l][r] = max(dp[l][r], tmp);
33     }
34     return dp[l][r];
35 }
36 
37 int main()
38 {
39     while(scanf("%s", s+1) && strcmp(s+1, "end"))
40     {
41         memset(dp, -1, sizeof(dp));
42         cout<< dfs(1, strlen(s+1))*2 <<endl;
43     }
44 }
View Code

递推:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <vector>
 6 #include <cmath>
 7 #include <queue>
 8 #include <stack>
 9 #include <map>
10 #include <string>
11 #include <set>
12 using namespace std;
13 typedef long long LL;
14 const int INF = 2e9;
15 const LL LNF = 9e18;
16 const int MOD = 1e9+7;
17 const int MAXN = 100+10;
18 
19 char s[MAXN];
20 int dp[MAXN][MAXN];
21 
22 int main()
23 {
24     while(scanf("%s", s+1) && strcmp(s+1, "end"))
25     {
26         memset(dp, 0, sizeof(dp));
27         int n = strlen(s+1);
28         for(int len = 2; len<=n; len++)
29         {
30             for(int l = 1; l<=n-len+1; l++)
31             {
32                 int r = l+len-1;
33                 dp[l][r] = dp[l+1][r];
34                 for(int k = l+1; k<=r; k++)
35                 {
36                     int ismatch = (s[l]=='('&&s[k]==')')||(s[l]=='['&&s[k]==']');
37                     dp[l][r] = max(dp[l][r], dp[l+1][k-1]+dp[k+1][r]+ismatch);
38                 }
39             }
40         }
41         printf("%d\n", dp[1][n]*2);
42     }
43     return 0;
44 }
View Code

 

posted on 2017-11-30 09:21  h_z_cong  阅读(274)  评论(0编辑  收藏  举报

导航