• 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
  • 相关阅读:
    如何用RadioButton做一个底部的切换栏
    自定义有监听器的ScrollView
    ViewPager的使用小技巧
    什么时候用Application的Context,什么时候用Activity的Context
    让改变输入法回车键的图标
    墙内下载DropBox离线安装包的方法
    巧用用layer-list做一个卡片背景
    LeakCanary中英文文档+使用例子
    让你的APK瘦成一道闪电
    用一张图片实现按钮按下和普通效果的样式
  • 原文地址:https://www.cnblogs.com/DOLFAMINGO/p/7927421.html
Copyright © 2020-2023  润新知