Description
We give the following inductive definition of a “regular brackets” sequence:
- the empty sequence is a regular brackets sequence,
- if s is a regular brackets sequence, then (s) and [s] are regular brackets sequences, and
- if a and b are regular brackets sequences, then ab is a regular brackets sequence.
- no other sequence is a regular brackets sequence
For instance, all of the following character sequences are regular brackets sequences:
(), [], (()), ()[], ()[()]
while the following character sequences are not:
(, ], )(, ([)], ([(]
Given a brackets sequence of characters (a_{1}a_{2} … a_{n}), your goal is to find the length of the longest regular brackets sequence that is a subsequence of (s). That is, you wish to find the largest m such that for indices (i_{1}, i_{2}, …, i_{m}) where (1 ≤ i_{1} < i_{2} < … < i_{m} ≤ n, a_{i1}a_{i2} … a_{im}) is a regular brackets sequence.
Given the initial sequence ([([]])]
, the longest regular brackets subsequence is [([])]
.
Input
The input test file will contain multiple test cases. Each input test case consists of a single line containing only the characters (
, )
, [
, and ]
; each input test will have length between (1) and (100), inclusive. The end-of-file is marked by a line containing the word "end" and should not be processed.
Output
For each input case, the program should print the length of the longest possible regular brackets subsequence on a single line.
Sample Input
((()))
()()()
([]])
)[)(
([][][)
end
Sample Output
6
6
4
0
6
Source
Solution
题意简述:给出一个的只有'(',')','[',']'四种括号组成的字符串,求最多
有多少个括号满足题目里所描述的完全匹配。
本题考察了区间DP,可以称为是区间DP的模板题。
区间DP的板子(来源:https://blog.csdn.net/qq_40772692/article/details/80183248):
for (int len = 1; len <= n; len++)//枚举长度
{
for (int j = 1; j + len <= n + 1; j++)//枚举起点,ends<=n
{
int ends = j + len - 1;
for (int i = j; i < ends; i++)//枚举分割点,更新小区间最优解
{
dp[j][ends] = min(dp[j][ends], dp[j][i] + dp[i + 1][ends] + something);
}
}
}
令(dp[i][j])为区间(i)~(j)中最长合法序列的长度。
首先,可以直接判断输入的字符串的第(i)位和第(j)位是否匹配,如果能成功匹配,就更新(dp[i][j] = dp[i + 1][j - 1] + 2)。
在这个基础上,枚举分割点(k),更新小区间内的最优解。
为了方便存储,我们将字符串整体向右移动(1)位。
最后输出(dp[1][字符串长度])即可。
Code
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cctype>
using namespace std;
inline int gi()
{
int f = 1, x = 0; char c = getchar();
while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar();}
while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar();}
return f * x;
}
char s[103];
int dp[103][103];
int main()
{
while (scanf("%s", s + 1) != EOF)//将输入的字符串整体右移1位
{
memset(dp, 0, sizeof(dp));//dp数组清零
int len = strlen(s + 1);//字符串长度
if (s[1] == 'e') return 0;//输入结束
/*开始区间DP*/
for (int i = 1; i <= len; i++)//枚举长度
{
for (int j = 1; j + i <= len + 1; j++)//枚举起点
{
int k = j + i - 1;//终点
if ((s[j] == '(' && s[k] == ')') || (s[j] == '[' && s[k] == ']')) //如果s[i]和s[j]相匹配
{
dp[j][k] = dp[j + 1][k - 1] + 2;//就进行状态转移
}
for (int l = j; l < k; l++)//枚举分割点
{
dp[j][k] = max(dp[j][k], dp[j][l] + dp[l + 1][k]);//进行状态转移
}
}
}
printf("%d
", dp[1][len]);//输出答案,记得换行
}
return 0;//结束
}