洛谷 题解 UVA1626 【括号序列 Brackets sequence】

时间:2021-09-27 08:12:50

看还没有人发记搜的题解,赶紧来发一篇

我们定义dp[i][j]为区间i~j内最少添加几个括号才能把这个串变成正规括号序列。

考虑四种情况

  1. i>j不存在这种子串,返回0

  2. i==j子串长度为1无论是"[","]","(",")"都是要消耗1的,返回1

  3. s=(s')或s=[s']那么返回的是DP(i+1,j-1)

  4. 其他情况,枚举断点,详见代码

至于输出嘛.....不会,看紫书的,输出代码的解释看看楼上吧,这里就不详细解释了

代码:

#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
int T,n;
string s;
int dp[110][110];//记忆
inline int DP(int l,int r)//记搜
{
    if(l==r)return dp[l][r]=1;//②
    if(l>r)return dp[l][r]=0;//①
    if(dp[l][r]!=INF)return dp[l][r];//记忆化
    if(s[l-1]=='('&&s[r-1]==')'||s[l-1]=='['&&s[r-1]==']')dp[l][r]=min(dp[l][r],DP(l+1,r-1));//③
    for(int i=l;i<r;i++)//枚举i~j的断点
    {
        dp[l][r]=min(dp[l][r],DP(l,i)+DP(i+1,r));//④
    }
    return dp[l][r];
}
inline void print(int l,int r)//输出
{
    if(l>r)return;
    if(l==r)
    {
        if(s[l-1]=='('||s[l-1]==')')
            cout<<"()";
        if(s[l-1]=='['||s[l-1]==']')
            cout<<"[]";
        return;
    }
    if(dp[l][r]==dp[l+1][r-1]&&((s[l-1]=='('&&s[r-1]==')')||(s[l-1]=='['&&s[r-1]==']')))
    {
        cout<<s[l-1];
        print(l+1,r-1);
        cout<<s[r-1];
    }
    else
    {
        for(int i=l;i<r;i++)
        {
            if(dp[l][r]==dp[l][i]+dp[i+1][r])
            {
                print(l,i);
                print(i+1,r);
                return;
            }
        }
    }
}
int main()
{
    scanf("%d",&T);
    getchar();
    while(T--)
    {
        memset(dp,0x3f,sizeof(dp));
        getline(cin,s);
        getline(cin,s);
     //这里要小心,输入的可能是空串!!!!!!!!坑了我很久了
        int n=s.size();
        //cout<<n<<" "<<s<<endl;
        if(!n)
        {
            cout<<endl<<endl;
            continue;
        }
        DP(1,n);
        //cout<<DP(1,n)<<endl;
        print(1,n);
        cout<<endl;
        if(T)cout<<endl;//输出格式也要注意!!
    }
    return 0;
}