1804: 括号匹配(二)
时间限制: 1 Sec 内存限制: 64 MB[提交][状态][讨论版]
题目描述
给你一个字符串,里面只包含"(",")","[","]"四种符号,请问你需要至少添加多少个括号才能使这些括号匹配起来。
如:
[]是匹配的
([])[]是匹配的
((]是不匹配的
([)]是不匹配的
如:
[]是匹配的
([])[]是匹配的
((]是不匹配的
([)]是不匹配的
输入
第一行输入一个正整数N,表示测试数据组数(N<=10) 每组测试数据都只有一行,是一个字符串S,S中只包含以上所说的四种字符,S的长度不超过100
输出
对于每组测试数据都输出一个正整数,表示最少需要添加的括号的数量。每组测试输出占一行
样例输入
4
[]
([])[]
((]
([)]
样例输出
0
0
3
2
来源
区间DP
转:
题意是说给一个字符串,包含'(',')','[',']'四种字符,判断至少需要添加几个字符使所给字符串括号匹配。
区间型动态规划,设dp[i][j]表示在字符串s中i位置到j位置所需要添加的最少的字符(i <= j)
有两种情况:
1、dp[i][j] = dp[i+1][j] + 1;
表示:在i到j之间没有与s[i]相匹配的括号,则必须添加一个字符来与之匹配,问题就转化为:从i+1位置到j位置所需要添加的最少的字符+1。
2、dp[i][j] = min{ dp[i+1][k-1] + dp[k+1][j] }; (i < k <= j)
表示:在i到j之间找到一个k使得s[i]与s[k]相匹配,则问题就转化为求:从i+1到k-1所需要添加的最少字符个数+从k+1到j之间所需要添加的最少字符个数(即dp[i+1][k-1] + dp[k+1][j])。因为k可能有多个,所以在其中所有的k的情况中取最小的。
求出两种情况后,这两种之间再求最小值,可以直接把dp[i][j]的初始值赋为dp[i+1][j]+1,然后进行第二种情况的求解
动态转移方程出来之后需要判断写几层循环和每层循环的起点和终点,从方程可以看出,有3层循环(i, j, k),对于dp[i][j]来说,必须先求出i之后的行的前j个,所以有两种循环的方法,我用的是第二种方法,感觉相对好理解。如下图。
方式一:从左往右更新 方式二:从下往上更新
初始化:只有一个字符时至少添加一个字符,所以dp[i][i] = 1;
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; char str[110]; int judge(int x,int y){//判断str[x]和str[y]是否配对 if(str[x]=='('&&str[y]==')'||str[x]=='['&&str[y]==']') return 1; else return 0; } int main(){ int N; scanf("%d",&N); int dp[110][110]; while(N--){ memset(dp,0,sizeof(dp)); scanf("%s",str); int len=strlen(str); for(int i=0;i<len;i++){ dp[i][i]=1; } for(int i=len-2;i>=0;i--){ for(int j=i;j<len;j++){ dp[i][j]=dp[i+1][j]+1;//赋初值为第一种情况(在i和j之间没有str[i]的),因为有两种情况并且最后要取两种情况的最小值,所以先给初始情况赋值为第一种情况 //(一共是两种情况,第一种是i和j之间没有字符可以匹配str[i],所以需要在i和j之间加一个括号,问题就转化为在第i+1和j之间需要加的括号数+1 //另一种是i和j之间本身就存在着和str[i]搭配的括号str[k],那么问题就转化为在第i+1和第k-1之间需要加的最小值和在k+1和j之间需要加的最小括号数的和) for(int k=i+1;k<=j;k++){ if(judge(i,k)){//在i跟j之间存在着str[i]的配对括号 dp[i][j]=min(dp[i][j],dp[i+1][k-1]+dp[k+1][j]);//因为k可能有多个,所以在所有的情况中取最小的 } } } } printf("%d\n",dp[0][len-1]); } return 0; }