题意: 给出一个由 '(', ')', '[', ']' 组成的序列, 求最长的合法括号序列的长度.
思路:
一开始我的想法是dp[i][j]维护i到j之间合法序列的长度. 然后单开数组维护这个区间头上多出的(和[,以及尾上的)和], 但是这样是不对的. 因为同样是i到j的区间, 可能会有不同个数的多余括号. 这样就产生了状态重叠(多个状态用了同一个位置表示). 这样, 就只能开4维空间, 但这在时间及空间上是不允许的.
实际上, 合法括号的情况包括: ①内部嵌套合法括号 以及 ②多个括号挨着. 另外, 因为是 子序列, 所以中间冗余的括号是不会影响的. 所以我们考虑:
①dp[i][j]=dp[i+1][j-1]+2 (当i位置和j位置是匹配的括号)
②dp[i][j]=dp[i][k]+dp[k][j] (for k in i to j)
即可.
代码:
//#include<bits/stdc++.h>
#include <cstring>
#include <cstdio>
#include <iostream>
using namespace std;
void debug_out() {
cerr << '\n';
}
template<typename T, typename ...R>
void debug_out(const T &f, const R &...r) {
cerr << f << " ";
debug_out(r...);
}
#define debug(...) cerr << "[" << #__VA_ARGS__ << "]: ", debug_out(__VA_ARGS__);
typedef long long ll;
const int M = 2e5 + 5;
const int inf = 1e9 + 5;
const int mod = 1e9 + 7;
char a[205];
int n;
int dp[205][205];
void solve() {
for (int len = 1; len <= n; len++) {
for (int s = 0; s < n; s++) {
int t = s + len - 1;
int tmp=0;
if(a[s]=='['&&a[t]==']'){
tmp=max(tmp,dp[s+1][t-1]+2);
}else if(a[s]=='('&&a[t]==')'){
tmp=max(tmp,dp[s+1][t-1]+2);
}
for(int i=s;i<=t;i++){
tmp=max(tmp,dp[s][i]+dp[i][t]);
}
dp[s][t]=tmp;
}
}
/*
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
printf("%d ",dp[i][j]);
}
puts(" ");
}
*/
printf("%d\n",dp[0][n-1]);
}
int main() {
while (~scanf("%s", a)) {
if(strcmp(a,"end")==0)break;
n = strlen(a);
memset(dp, 0, sizeof(dp));
solve();
}
return 0;
}
毒瘤POJ, 空间开105就是RE.