【题目描述】
我们用以下规则定义一个合法的括号序列:
(1)空序列是合法的 (2)假如S是一个合法的序列,则 (S) 和[S]都是合法的 (3)假如A 和 B 都是合法的,那么AB和BA也是合法的
例如以下是合法的括号序列:
(), [], (()), ([]), ()[], ()[()]
以下是不合法括号序列:
(, [, ], )(, ([]), ([()
现在给定一些由'(', ')', '[', ,']'构成的序列 ,请添加尽量少的括号,得到一个合法的括号序列。
【题目链接】
CodeVS 3657 括号序列
【解题思路】
经典区间DP,设$f[l][r]$表示将序列$[l, r]$补成合法括号序列最少的括号数。
转移如下,用$S$代表原序列: $$f[l][r] = min: \\ f[l + 1][r - 1],when\ S_l\ can\ match\ with\ S_r, \\ min\{\ f[l][k] + f[k + 1][r]\ \},k \in [l, r)$$ 即分别考虑合法括号序列定义的规则2和规则3,取最小值。
边界: $$f[i][i] = 1$$ (单独一个括号是不合法的,需要补一个括号)
依旧按照区间长度从短到长计算。
【AC代码】
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <climits>
#define MAXN 100
char S[MAXN + 1];
int f[MAXN][MAXN];
int main(){
scanf("%s", S);
int n = strlen(S);
for(int i = 0; i < n; i++) f[i][i] = 1;
for(int len = 1; len < n; len++){
for(int l = 0; l < n - len; l++){
int r = l + len;
int &ans = f[l][r];
ans = INT_MAX;
if((S[l] == '(' && S[r] == ')')
|| (S[l] == '[' && S[r] == ']')
) ans = std::min(ans, f[l + 1][r - 1]);
for(int k = l; k < r; k++){
ans = std::min(ans, f[l][k] + f[k + 1][r]);
}
}
}
printf("%d\n", f[0][n - 1]);
return 0;
}
就是这样啦。