题意
给一串包含中括号和小括号的字符串,求其括号匹配正常的顺序(不一定连续)子串中的(最长串)
分析
状态
区间问题的一般处理方法:设 dp[i][j]⇔与j间最长满足要求子串长度
状态转移方程
- 如果这个区间两个端点的括号是匹配的,那么它可以是由去掉两端点的串加上2转移而来,比如([])
dp[i][j]=max(dp[i][j],dp[i+1][j−1]+2) - 它也可能是由它的两个串拼在一起而成的,比如()[]
dp[i][j]=max(dp[i][j],dp[i][i]+dp[i+1][j]→dp[i][j−1]+dp[j][j])
初始化
这题数据量小,可以记忆化搜索,就不用考虑初始化的问题。
如果递推的话,先全部初始化为零,然后把相邻位置且匹配的区间初始化为2即可。
DP顺序
记忆化搜索不用说。递推时,观察状态转移方程,两个端点都在动,然而可以确定的是,状态转移依赖的区间的长度都比待求的小。因此可以以区间长度递增为DP顺序(从长度为3开始)。
最终解
自然是 dp[0][n]
AC代码
//POJ 2955 Brackets
//AC 2016-5-25 16:20:35
//DP
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cctype>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <set>
#include <string>
#include <map>
#include <queue>
#include <deque>
#include <list>
#include <sstream>
#include <stack>
using namespace std;
#define cls(x) memset(x,0,sizeof x)
#define inf(x) memset(x,0x3f,sizeof x)
#define neg(x) memset(x,-1,sizeof x)
#define ninf(x) memset(x,0xc0,sizeof x)
#define st0(x) memset(x,false,sizeof x)
#define st1(x) memset(x,true,sizeof x)
#define INF 0x3f3f3f3f
#define lowbit(x) x&(-x)
#define bug cout<<"here"<<endl;
//#define debug
int dp[110][110];
char seq[110];
bool thesame(int a,int b)
{
char &l=seq[a],&r=seq[b];
if(l=='('&&r==')')
return 1;
if(l=='['&&r==']')
return 1;
return 0;
}
int dyna(int a,int b)
{
if(dp[a][b]==-1)
{
if(a>=b)
dp[a][b]=0;
else
{
for(int i=0;a+i<b;++i)
dp[a][b]=max(dp[a][b],dyna(a,a+i)+dyna(a+i+1,b));
if(thesame(a,b))
dp[a][b]=max(dp[a][b],dyna(a+1,b-1)+2);
}
}
return dp[a][b];
}
int main()
{
#ifdef debug
freopen("E:\\Documents\\code\\input.txt","r",stdin);
freopen("E:\\Documents\\code\\output.txt","w",stdout);
#endif
while(scanf("%s",seq)!=EOF&&seq[0]!='e')
{
neg(dp);
printf("%d\n",dyna(0,strlen(seq)-1));
}
return 0;
}