题目概述
给出一个长度不超过 100 的括号序列( ()[] ),一个合法的括号序列要么是空序列,要么满足:
- 如果
s
是合法序列,则
(s),[s] 也是合法序列。 - 如果 x,y 是合法序列,则 xy 也是合法序列。
求给出括号序列的最长合法子序列的长度。
解题报告
显然是区间DP,定义 f[i][j] 表示 [i,j] 的最优解,那么根据题目有两种转移方式:
- f[i+1][j−1]+check(i,j) 。
- f[i][k]+f[k+1][j] 。
其中 check(i,j) 表示 i,j 是否匹配。
示例程序
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=100;
int n,f[maxn+5][maxn+5];char s[maxn+5];
#define check(i,j) (s[i]=='('&&s[j]==')'||s[i]=='['&&s[j]==']')
int main()
{
freopen("program.in","r",stdin);
freopen("program.out","w",stdout);
for (scanf("%s",s+1);strcmp(s+1,"end");scanf("%s",s+1))
{
n=strlen(s+1);for (int i=1;i<n;i++) f[i][i+1]=check(i,i+1);
for (int len=3;len<=n;len++)
for (int i=1,j=i+len-1;i<=n-len+1;i++,j++)
{
f[i][j]=f[i+1][j-1]+check(i,j);
for (int k=i;k<j;k++) f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]);
}
printf("%d\n",f[1][n]*2);
}
return 0;
}