- 题目描述 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][j?1]};即令S1合法后,S可合法。
若S0形如(S1或[S1,f[i][j]=min{f[i][j],f[i][j?1]+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]},i≤k<j;即把序列分成两部分分别使其合法。
- Code
#include <cstdio>
#include <cstring>
#include <algorithm>
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;
}
时间: 2024-11-06 07:20:36