• POJ 2955 Brackets


    我们给出了“正则括号”序列的以下归纳定义:

    • 空序列是一个 正则方括号序列;
    • 如果s是正则方括号序列,那么(s)和[s]是正则括号序列;
    • 如果a和b是正则括号序列,则ab是正则括号序列;
    • 没有其他序列是正则括号序列。

    例如,以下所有字符序列都是正则括号序列:

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

    而下列字符序列不是:

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

    思路

    状态表示:
    (f(i,j)):字符串(s)的子区间([i,j])的最长正则括号子序列的长度。

    状态转移:

    1. 如果字符串(s)是空串,或长度为(1),那么最长正则括号子序列肯定是(0)
    2. 如果字符串(s)的长度为2, 那么当(s=="()")或者(s=="[]")的时候,最长正则括号子序列的长度为(2);否则长度为(0)
    3. (s[l]=='(') 并且 (s[r]==')')或者(s[l]=='[') 并且 (s[r]==']') 时,有如下转移方程:

    [f(l,r)=f(l+1,r-1)+2 ]

    1. 如果不是((s'))或者([s'])的情况,我们可能会想到如下的转移方程:

    [f(l,r)=max(f(l+1,r),f(l,r-1)) ag {1} ]

    但最长正则括号子序列可能是由若干正则子序列拼接而成的,如(s="()()"),这时我们需要去枚举(k in [l+1,r-1])

    [f(i,j)=max(f(i,j),f(i,k)+f(k+1,j)) ag {2} ]

    可以发现,((1))(k)(l)(r-1)时的特殊情况,结合((1)(2))可得:

    [f(i,j)=max(f(i,j),f(i,k)+f(k+1,j)) k in [l,r-1] ]

    综上:

    • 如果(s)形如((s'))([s’]),转移到(s[l+1 sim r-1])
    • 如果(s)至少有两个字母,则可以分成ab,转移到(s[l_asim r_a]+s[l_b+r_b])
    const int N=110;
    int f[N][N];
    string s;
    int n;
    
    bool match(int x,int y)
    {
        return s[x] == '(' && s[y] == ')' || s[x] == '[' && s[y] == ']';
    }
    
    int main()
    {
        while(cin>>s)
        {
            if(s == "end") break;
    
            memset(f,0,sizeof f);
    
            n=s.size();
            for(int i=n-1;i>=0;i--)
                for(int j=i+1;j<n;j++)
                {
                    if(match(i,j)) f[i][j]=f[i+1][j-1]+2;
    
                    for(int k=i;k<j;k++)
                        f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]);
                }
    
            cout<<f[0][n-1]<<endl;
        }
        //system("pause");
        return 0;
    }
    
  • 相关阅读:
    索引器
    异常
    C#各版本
    构造函数
    值类型和引用类型
    面向对象聊天机器人
    linux 系统快捷键
    linux 系统常用设置
    linux 系统介绍
    linux 命令学习.txt
  • 原文地址:https://www.cnblogs.com/fxh0707/p/14655368.html
Copyright © 2020-2023  润新知