题解【POJ2955】Brackets

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

Stanford Local 2004

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\n", dp[1][len]);//输出答案,记得换行
	}
	return 0;//结束
}
posted @ 2019-07-03 10:59  csxsi  阅读(216)  评论(0编辑  收藏  举报