Codevs3657括号序列题解

  • 题目描述 Description
    我们用以下规则定义一个合法的括号序列:
    (1)空序列是合法的
    (2)假如 S 是一个合法的序列,则 (S) [S] 都是合法的
    (3)假如 A B 都是合法的,那么 AB BA 也是合法的
    例如以下是一些合法的括号序列:
    (),[],(()),([]),()[],()[()]
    以下是一些不合法括号序列的:
    (,[,],)(,([]),([()
    现在给定一些由 (,),[,] 构成的序列 ,请添加尽量少的括号,得到一个合法的括号序列。

  • 输入描述 Input Description
    输入包括号序列 S 。含最多100个字符(四种字符: (,),[] ),都放在一行,中间没有其他多余字符。

  • 输出描述 Output Description
    使括号序列S成为合法序列需要添加最少的括号数量。

  • 样例输入 Sample Input
    ([()

  • 样例输出 Sample Output
    2

  • 数据范围及提示 Data Size & Hint
    【样例说明】
    最少添加2个括号可以得到合法的序列: ()[()] ([()])
    【数据范围】
    S 的长度 100 (最多100个字符)

  • 题解
    又是序列的题目。先一看不能顺着推,再一看不能倒着推,所以想到区间dp。以 f[i][j] 表示把区间 [i,j] 添成合法括号所需的最小括号数。
    设某段序列为 S0 ,它对应区间为 [i,j] ,括号数为 f[i][j] .
    S0 形如 (S1) [S1] f[i][j]=min{f[i][j],f[i+1][j1]}; 即令 S1 合法后, S 可合法。
    S0 形如 (S1 [S1 f[i][j]=min{f[i][j],f[i][j1]+1}; 即令 S1 合法后, S 可在最后添加一个括号后合法。
    同理,若 S0 形如 S1) S1] f[i][j]=min{f[i][j],f[i+1][j]+1};
    无论 S0 是什么情况,都有 f[i][j]=min{f[i][j],f[i][k]+f[k+1][j]},ik<j; 即把序列分成两部分分别使其合法。

  • Code

#include 
#include 
#include 
using namespace std;
const int maxn = 110;
const int oo = 0x3f3f3f;
char ch[maxn];
int f[maxn][maxn], n;
void init()
{
    scanf("%s", &ch);
    n = strlen(ch);
    for(int i = 1; i <= n; ++i) f[i][i] = 1;
}
void work()
{
    for(int p = 1; p < n; ++p) for(int i = 1; i <= n - p; ++i)
    {
        int j = p + i;
        f[i][j] = oo;
        if((ch[i - 1] == '(' && ch[j - 1] == ')') || (ch[i - 1] == '[' && ch[j - 1] == ']'))
            f[i][j] = f[i + 1][j - 1];
        if(ch[i - 1] == '(' || ch[i - 1] == '[') f[i][j] = min(f[i][j], f[i][j - 1] + 1);
        if(ch[j - 1] == ')' || ch[j - 1] == ']') f[i][j] = min(f[i][j], f[i + 1][j] + 1);
        for(int k = i; k < j; ++k) f[i][j] = min(f[i][j], f[i][k] + f[k + 1][j]);
    }
    printf("%d", f[1][n]);
}
int main()
{
    init();
    work();
    return 0; 
}

你可能感兴趣的:(OI党坚毅的步伐)