【题目描述】
给定一个括号字符串,让你求出最大括号匹配的括号数
【思路】
dp[i][j]表示区间i到j中的最大括号匹配数,分析发现,它与小区间的括号问题是相关联的,具有最优子结构性质。这是一个区间dp问题。
比如:假定我们求()))()这个括号串的最大括号匹配数,即f(0, 5)的结果
显然,f(0, 5) = f(0, 1) + f(1, 5)
f(0, 5) = f(0, 2) + f(2, 5)等等。。。我们要求出大区间的结果必须先求出小区间的结果,这就是区间dp的基本思想!
关于区间dp,这是我第一次接触到,同类型的问题还有矩阵链乘
核心就是大区间分成多个小区间,只要把小区间的结果算出,大区间就算出了。遍历顺序是对角线的方向,和以往的有点不同,刚开始在这里也有点难理解
参考代码:
#include<iostream>
using namespace std;
const int maxn = 100;
string str;
int length;
int dp[maxn][maxn];
int DP()
{
//base
for(int i = 0;i <= length - 1;i++)
{
dp[i][i] = 0;
}
for(int len = 1;len <= length - 1;len++)
{
for(int i = 0;i <= length - 1;i++)
{
int j = len + i;
if(str[i] == '(' && str[j] == ')') //即使匹配也不一定就是 dp[i][j] = dp[i + 1][j - 1] + 2;
{ //可能是这种情况()))()
dp[i][j] = dp[i + 1][j - 1] + 2;
} //所以还是要进行下面的分区间筛选
int max_res = dp[i][j];
for(int k = i;k < j;k++)
{
if(dp[i][k] + dp[k + 1][j] > max_res)
max_res = dp[i][k] + dp[k + 1][j];
}
dp[i][j] = max_res;
}
}
//print dp
for(int i = 0;i <= length - 1;i++)
{
for(int j = 0;j <= length - 1;j++)
{
cout << dp[i][j] << " ";
}
cout << endl;
}
return dp[0][length - 1];
}
int main()
{
cin >> str;
length = str.length();
cout << DP() << endl;
return 0;
}
这题还可以变一下,就是求括号串的最少添加数,那就是总字符串长度减去最大匹配数就可以了!