求给定序列匹配括号的最大子列
令dp[ i ][ j ]表示i到j中匹配的最大子列的长度
初始化 dp[ i ][ i ] = 0
那么
1.dp[ i ][ j ] = dp[ i ][ j-1 ],如果第j个括号是左括号,则不可能与之前的括号匹配,所以最大匹配子列长度不变
2.dp[ i ][ j ] = max(dp[ i ][ j-1 ],max( dp[ i ][ k -1 ] + dp[ k+1 ][ j -1 ] +2)),如果是右括号
我们来着重讨论这个右括号的情况,
求dp[i][j]时,第j个括号是右括号无非会导致两种情况
1.第j个括号不匹配
2.第j个括号与第i~j-1个括号中的一个相匹配
如果第j个括号不匹配,实际上与情况1一致,这就出现了上面max中的第一项
如果第j个括号匹配i~j-1中的某个编号为k的括号,那么dp[i][j]表示第i到第j匹配的最大子列长度就表示为
第i到第k-1位匹配的最大子列长度+第k+1到j-1位匹配的最大子列长度+2(匹配的第j和第k位括号贡献的长度)
要找到能使dp[i][j]最大的那个k
这就是上面max中第二项的解释
#include<iostream>
#include<string>
#include<memory.h>
using namespace std;
int dp[101][101];
int main()
{
char s[102];
cin.getline(s,101);
while(strcmp(s,"end"))
{
int len=1;
while(s[len]!='\0'){
len++;
}
for(int i=len;i>=1;i--){
s[i]=s[i-1];
}
memset(dp,0,sizeof(dp));
for(int j=2;j<=len;j++){
for(int i=j-1;i>=1;i--){
dp[i][j]=dp[i][j-1];
if(s[j]=='['||s[j]=='('){
continue;
}
else{
for(int k=i;k<j;k++){
if((s[k]=='['&&s[j]==']')||(s[j]==')'&&s[k]=='(')){
dp[i][j]=max(2+dp[i][k-1]+dp[k+1][j-1],dp[i][j]);
}
}
}
}
}
cout<<dp[1][len]<<endl;
cin.getline(s,101);
}
}