zoukankan      html  css  js  c++  java
  • 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
    ", 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
    ", dp[1][n]*2);
    42     }
    43     return 0;
    44 }
    View Code
  • 相关阅读:
    POJ 1611 The Suspects
    POJ 2001 Shortest Prefixes(字典树)
    HDU 1251 统计难题(字典树 裸题 链表做法)
    G++ C++之区别
    PAT 乙级 1013. 数素数 (20)
    PAT 乙级 1012. 数字分类 (20)
    PAT 乙级 1009. 说反话 (20)
    PAT 乙级 1008. 数组元素循环右移问题 (20)
    HDU 6063 17多校3 RXD and math(暴力打表题)
    HDU 6066 17多校3 RXD's date(超水题)
  • 原文地址:https://www.cnblogs.com/DOLFAMINGO/p/7927421.html
Copyright © 2011-2022 走看看