最大括号
一、题目
我们给出以下“正则括号”序列的归纳定义:
空序列是一个普通的括号序列
如果s是一个正则方括号序列,那么(s)和[s]是正则方括号序列
如果a和b是正则中括号序列,那么ab就是一个正则中括号序列。
没有其他序列是一个普通的括号序列
例如,下面所有的字符序列都是正则括号序列:
(), [], (), (), ()[], ()[()]
而下列字符序列不是:
(,],)(, ()], ()
给定一个括号的字符序列a1a2…an,你的目标是找到的长度最长正则括号序列的子序列s。
样例:给定初始序列([([]])],子序列中最长的正则括号为[([])]。
二、输入
输入测试文件将包含多个测试用例。每个输入测试用例由一行组成,其中只包含字符(、)、[和];每个输入测试的长度都在1到100之间。文件结束由包含单词“end”的行标记,不应该被处理。
三、输出
对于每个输入情况,程序应该将最长的可能的正则括号子序列的长度打印在一行上。
四、样例输入输出
Input
((()))
()()()
([]])
)[)(
([][][)
end
Output
6
6
4
0
6
五、解题思路
区间dp例题。将大区间分割成小区间。
遍历所有长度的区间,i为左端点,j为右端点,如果ij为“()” “[]”,则转移方程为f[i][j]=f[i+1][j-1]+2。
枚举区间断点k,转移方程为f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]),其中i<=k<=j,即对选不选k做一个判断。 最后f[0][n]即最长的区间结果即为答案。
六、样例代码
#include<iostream>
#include<string>
#include<string.h>
using namespace std;
int f[110][110];
string s;
int len;
int main()
{
while(1)
{
cin>>s;
if(s=="end") break;
for(int i=0;i<110;i++)
for(int j=0;j<110;j++)
f[i][j]=0;
len=s.length();
for(int l=2;l<=len;l++) //遍历长度
{
for(int i=0;i<=len-l;i++) //左端点
{
int j=l+i-1; //右端点
if((s[i]=='('&&s[j]==')')||(s[i]=='['&&s[j]==']')) //为()【】
{
f[i][j]=f[i+1][j-1]+2; //选择
}
for(int k=i;k<=j;k++) //断点
{
f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]); //选不选K
}
}
}
cout<<f[0][len-1]<<endl;
}
return 0;
}