区间动态规划-括号匹配(SOJ 1069)
题意:给出由$(,),[,]$四个字符组成的序列$S$,输出符合要求的括号序列的最大长度。下面是符合要求的括号序列的递归定义:
(1)空序列;
(2)如果$S$是,那么$(S)$和$[S]$也是;
(3)如果$S$和$T$是,那么$ST$也是。
分析:这个问题和矩阵链最优乘法(参考《算法导论》)在分析子结构时有很多相似之处。
定义$dp[i][j]$为子串$S[i..j]$的符合要求的括号序列的最大长度,则
根据(2)我们可得如果$S[i]=S[j]$,则$dp[i][j]=dp[i+1][j-1]+2$;
根据(3)我们可得$dp[i][j]=\max\{dp[i][j],dp[i][k]+dp[k+1][j],i\le k\le j-1\}$.
代码:
#include<iostream> #include<algorithm> #include<cstring> using namespace std; char s[102]; int dp[102][102]; int main() { int i, j, k; int len; int delta; while (~scanf("%s", s+1) && s[1]!='e') { memset(dp, 0, sizeof(dp)); len = strlen(s+1); for (delta = 2; delta <= len; delta++) { for (i = 1; i <= len+1-delta; i++) { j = i + delta - 1; if ((s[i] == '(' && s[j] == ')') || (s[i] == '[' && s[j] == ']')) dp[i][j] = dp[i + 1][j - 1] + 2; for (k = i;k<j; k++) dp[i][j] = max(dp[i][j], dp[i][k] + dp[k + 1][j]); } } printf("%d\n", dp[1][len]); } return 0; }