我们给出了“正则括号”序列的以下归纳定义:
- 空序列是一个 正则方括号序列;
- 如果s是正则方括号序列,那么(s)和[s]是正则括号序列;
- 如果a和b是正则括号序列,则ab是正则括号序列;
- 没有其他序列是正则括号序列。
例如,以下所有字符序列都是正则括号序列:
(),[], (()), ()[], ()[()]
而下列字符序列不是:
(,],)(,([)], ([(]
思路
状态表示:
(f(i,j)):字符串(s)的子区间([i,j])的最长正则括号子序列的长度。
状态转移:
- 如果字符串(s)是空串,或长度为(1),那么最长正则括号子序列肯定是(0);
- 如果字符串(s)的长度为2, 那么当(s=="()")或者(s=="[]")的时候,最长正则括号子序列的长度为(2);否则长度为(0)。
- 当 (s[l]=='(') 并且 (s[r]==')')或者(s[l]=='[') 并且 (s[r]==']') 时,有如下转移方程:
[f(l,r)=f(l+1,r-1)+2
]
- 如果不是((s'))或者([s'])的情况,我们可能会想到如下的转移方程:
[f(l,r)=max(f(l+1,r),f(l,r-1)) ag {1}
]
但最长正则括号子序列可能是由若干正则子序列拼接而成的,如(s="()()"),这时我们需要去枚举(k in [l+1,r-1]):
[f(i,j)=max(f(i,j),f(i,k)+f(k+1,j)) ag {2}
]
可以发现,((1))是(k)为(l)和(r-1)时的特殊情况,结合((1)(2))可得:
[f(i,j)=max(f(i,j),f(i,k)+f(k+1,j)) k in [l,r-1]
]
综上:
- 如果(s)形如((s'))或([s’]),转移到(s[l+1 sim r-1])。
- 如果(s)至少有两个字母,则可以分成ab,转移到(s[l_asim r_a]+s[l_b+r_b])。
const int N=110;
int f[N][N];
string s;
int n;
bool match(int x,int y)
{
return s[x] == '(' && s[y] == ')' || s[x] == '[' && s[y] == ']';
}
int main()
{
while(cin>>s)
{
if(s == "end") break;
memset(f,0,sizeof f);
n=s.size();
for(int i=n-1;i>=0;i--)
for(int j=i+1;j<n;j++)
{
if(match(i,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]);
}
cout<<f[0][n-1]<<endl;
}
//system("pause");
return 0;
}