Description
给定一个只包含{},(),[]的字符串,假设你能够在这个括号
字符串中的任意位置添加任何括号,你要做得就是在合适的位置
添加括号,使得所有括号都正确嵌套,若所给字符串中的括号完
美匹配,无需修改,请输出“SZTU_WOD YYDS!”;否则求能使得这
串字符每对括号都正确嵌套的最少添加数。
Input
输入包含多组测试数据,每组测试样例占一行,每行不超过100个字符。
Output
若所给字符串中的括号完美匹配,无需修改,请输出“SZTU_WOD YYDS!”;
否则求能使得这串字符每对括号都正确嵌套的最少添加数。
Sample Input
()
())
Sample Output
SZTU_WOD YYDS!
1
#include<stdio.h> #include<stack> #include<map> using namespace std; char s[110]; int main(){//原先栈的做法 int N,tot; scanf("%d",&N); while(N--){map<char,int>mp; stack<char>sign; tot=0; mp['(']=1;mp[')']=-1; mp['[']=2;mp[']']=-2; mp['{']=3;mp['}']=-3; //使用map来判断括号是否匹配 scanf("%s",s); for(int i=0;s[i];i++){ if(mp[s[i]]>0)sign.push(s[i]);//是左括号 else{//右括号 if(!sign.empty()){//栈非空 if(mp[sign.top()]+mp[s[i]]==0)sign.pop();//括号匹配 else tot++;//计数 } else tot++;//栈空时 } } while(!sign.empty()){//最后加上栈里的 sign.pop(); tot++; } printf("%d\n",tot); } return 0;}
首先需要理解的是该题与原先我们使用栈做的括号匹配有什么区别
如:
[]是匹配的
([])[]是匹配的
((]是不匹配的
([)]是不匹配的([(]是不匹配的
( [ ( ] 观察这个例子,我们按照该题的题意,我们可以很容易想到这个例子只需添加两个右括号即可满足题意,但是按照栈的做法,我们我们会发现得到的结果是4,因为按照栈的逻辑没有办法使得两个[ ]是得到匹配的,因此答案里多了2
那么我们只能寻找别的办法解决了
考虑使用动态规划解决
仔细观察题意我们不难发现,该题存在子问题结构
我们定义一个dp数组dp[ i ][ j ]表示下标从i到j的字符串需要添加的括号数量是多少(左闭右闭),而最小子问题就是 i = j时,此时只有一个括号必然需要添加一个括号进行匹配,其他情况可以初始化为0
那么如果下标为i和下标为j的括号是匹配的话,那么我们的当前问题就可以转换成dp[ i ][ j ]=dp[ i +1 ][ j - 1]
反之,我们需要对区间
[i,j]
内的区间进行遍历分割,如果有更小的值,就采用更小的,也即dp[i][j]=min(dp[i][j], dp[i][k] + dp[k+1][j]),因为存在这样的情况
[ [ [ ] ] ] [ [ [ ] ] ]至此我们就可以写代码了
#include<cstdio> #include<cstring> #include<stack> using namespace std; char buf[105]; int dp[105][105];//定义dp数组dp[i][j]表示从i到j需要补充的括号数 (左闭右闭) int maxn=0x3f3f3f3f; bool check(char a,char b){ return (a=='('&&b==')')||(a=='['&&b==']')||(a=='{'&&b=='}'); } int main(){ while((scanf("%s",buf))!=EOF){ int len=strlen(buf); for(int i=0;i<len;i++){ for(int j=0;j<=100;j++){ dp[i][j]=0; if(i==j){ dp[i][j]=1;//只有一个括号时必然需要补充一个括号 } } } for(int sizee=1;sizee<=len;sizee++){//从最小子问题开始求解 for(int i=0;i<len-sizee;i++){//起点 int j=i+sizee;//终点 dp[i][j]=maxn;//因为下面需要求较小值,因此初始化为最大值 if(check(buf[i],buf[j])){ dp[i][j]=dp[i+1][j-1];//如果起点和终点匹配那么当前问题=去掉匹配的括号的子问题的解 } //存在分割分割情况(比如"[[[]]][[[]]]"需要分成两部分考虑),应依次考虑所有分割情况 for(int k=i;k<j;k++){ dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]); } } } if(dp[0][len-1]==0){ printf("SZTU_WOD YYDS!\n"); }else{ printf("%d\n",dp[0][len-1]); } } return 0; }