题目描述
Hecy 又接了个新任务:BE 处理。BE 中有一类被称为 GBE。
以下是 GBE 的定义:
1. 空表达式是 GBE
2. 如果表达式 A 是 GBE,则 [A] 与 (A) 都是 GBE
3. 如果 A 与 B 都是 GBE,那么 AB 是 GBE
输入
输入仅一行,为字符串 BE
输出
输出仅一个整数,表示增加的最少字符数
样例输入
[])
样例输出
1
提示
【数据范围与提示】
对于 100% 的数据,输入的字符串长度小于 100。
题解
这道题是一个区间DP。
dp[i][j]表示i到j的区间内需要添加的最少括号数。
先来说说初始化。首先区间长度为1,必然dp值为1(必须加括号),然后枚举每一个dp[i][j]之前要把这个值赋为极大值。至于为什么不先把所有的dp都定为极大值,是因为如果区间l>r,那么这种情况的括号数应该0.这样是为了处理“()”和“[ ]”的情况,由于初值为1,但是实际上两个括号连接时答案是0,就相当于是用了l>r时dp为0的性质(当然特判也可以)。
如何转移?
枚举len表示区间长度,然后枚举左端点确定区间。
对于一个区间,必然由两个小区间的括号数相加得到。因此有dp[i][j]=dp[i][k]+dp[k+1][j],枚举断点k,然后在所有过程中取一个最小值。其次,如果枚举的第i个字符和第j个字符是括号配对的,那么显然这样不会消耗次数(里面的清完了,外面自然是OK的),因此当check(i,j)为true时,还有一种转移方式:min(dp[i][j],dp[i+1][j-1]),注意对于i+1==j,也就是()或者[ ] 的情况,转移肯定是dp[i+1][j-1](值为0)。
scanf("%s",s+1)表示把字符串的下表都+1,但是注意求长度len的时候也要s+1。
参考代码
#include<cstdio>
#include<cstring>
using namespace std;
int dp[200][200],lens;
char s[200];
int min1(int p,int q) { return p<q?p:q; }
bool check(int p,int q)
{
if(s[p]=='('&&s[q]==')') return 1;
if(s[p]=='['&&s[q]==']') return 1;
return 0;
}
int main()
{
scanf("%s",s+1);
lens=strlen(s+1);
for(int i=1;i<=lens;i++)
dp[i][i]=1;
for(int len=2;len<=lens;len++)
{
for(int l=1;l+len-1<=lens;l++)
{
int r=l+len-1;
dp[l][r]=707406378;
for(int k=l;k<r;k++)
dp[l][r]=min1(dp[l][r],dp[l][k]+dp[k+1][r]);
if(check(l,r))
dp[l][r]=min1(dp[l][r],dp[l+1][r-1]);
}
}
printf("%d",dp[1][lens]);
return 0;
}