CSP--DP专题之区间DP

CSP-DP专题(区间DP)

题目叙述

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 a1a2 … an, 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 i1, i2, …, im where 1 ≤ i1 < i2 < … < im ≤ n, ai1ai2 … aim 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.

输入样例:

((()))
()()()
([]])
)[)(
([][][)
end

Output和输出样例

For each input case, the program should print the length of the longest possible regular brackets subsequence on a single line.

输出样例:

6
6
4
0
6

思路叙述

题目是一道经典的区间DP问题,可以简称为括号问题。括号问题一般有两个相似的版本,这里会将两外一种也进行叙述:
题解算法
题目给出的求解要求是求出最长的合法括号子串,合法的要求是有能够匹配的"(" 和 “)”或匹配的 “[”
和“]”,或者整个子串为空。
具体的合法子串有下列四种:
如果S为合法的子串,则下列四种也为合法子串:
1、(S):在合法串两侧1有匹配的"(" 和 “)”
2、[S];在合法串两侧1有匹配的 “[” 和 “]”
3、S1S2;两个合法串的拼接也为合法串
4、空串为合法串

方便使用动态规划来解决问题,可以设计dp数组为dp[i][j],表示的意义是从 i 位置到 j 位置的最长子串个数。转移方程可以设计为:
1、由子问题的解合并而来:dp[i][j]=max(dp[i][k]+dp[k+1][j]) (i<k<j)
2、由子串的合法匹配而来:如果在合法串两侧1有匹配的"(" 和 “)”,或是在合法串两侧1有匹配的 “[” 和 “]” ,dp[i][j]=dp[i+1][j-1]+2
取两种情况的最大值即可。

拓展算法
另外一种求解要求是求出最小匹配花费,匹配花费的意思是需要添加多少个括号,来保证添加后的括号串是合法的,合法要求与上述相同。

同样适用动态规划来解决问题,设计dp数组dp[i][j],表示的意义是从 i 位置到 j 位置的保证括号串合法的最小添加括号数量。转移方程可以设计为:

1、由子问题的解合并而来:dp[i][j]=min(dp[i][k]+dp[k+1][j]) (i<k<j)
2、由子串的合法匹配而来:如果在合法串两侧有匹配的"(" 和 “)”,或是在合法串两侧1有匹配的 “[” 和 “]” ,dp[i][j]=dp[i+1][j-1]
3、由子串的添加括号而来:如果在合法串单侧有"(" 或 “)”,或是在合法串单侧有 “[” 和 “]” ,添加一个括号进行匹配即可保证合法,dp[i][j]=dp[i+1][j-1]+1

取以上三种情况的最小值即可。

实现源代码

#include<iostream>
#include<stdio.h>
#include<string>
using namespace std;
const int M=1e7;
string s;
int dp[105][105]; 

int dp_process()
{
    
    
	for(int i=0;i<=s.size();i++)
		for(int j=0;j<=s.size();j++)
			dp[i][j]=0;
	for(int length=2;length<=s.size();length++)
		for(int x=0;x+length-1<s.size();x++)
		{
    
    
			int max_lit_num=0;
			int clarify_num=0;
			for(int i=x;i<x+length-1;i++)
			{
    
    
				max_lit_num=max(max_lit_num,dp[x][i]+dp[i+1][x+length-1]);
			}
			if(s[x]=='(' && s[x+length-1]==')')
			clarify_num=dp[x+1][x+length-2]+2;
			else if(s[x]=='[' && s[x+length-1]==']')
			clarify_num=dp[x+1][x+length-2]+2;
			dp[x][x+length-1]=max(clarify_num,max_lit_num);
		}
    return dp[0][s.size()-1];
}

int main()
{
    
    
    cin>>s;
    while(s!="end"){
    
    
        int res=dp_process();
        printf("%d\n",res);
        cin>>s;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43942251/article/details/106169392
今日推荐