Week12作业-选做题-最长合法子序列

D-最长合法子序列

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 < … < imn, 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.

Output

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

思路:
  • 首先定状态,这里类似于例题,我们定义dp[i][j]为区间[i,j]中最长的合法子序列。

  • 确定初始情况:对于长度为1的区间,显然初始值为0,因为不合法。

  • 确定状态转移方程:

    • 对区间进行划分,dp[l][r]=max(dp[l][k],dp[k+1][r]),l<=k

    • 对于区间[l,r],上述划分未处理的一种情况在于str[l]与str[r]匹配。这种情况事实上对区间进行了两次划分。

      为什么不需要处理其余的划分的情况,比如三次甚至更多次的划分?因为我们将大的区间划分成小的区间的目的在于枚举各种可能的答案,因此需要确保所有可能的答案全部出现。一方面,其可能答案的来源在于此前len更小的区间,这些对应着划分成两部分;另一方面,对于str[l]与str[r]匹配的情况,这是此前没有包括的,所以需要额外判断。

实现:
#include
#include
#include
#include

using namespace std;

const int maxn = 110;
int dp[maxn][maxn];
string str;

bool check(int l,int r)
{
	if(str[l]=='(' && str[r]==')')return true;
	if(str[l]=='[' && str[r]==']')return true;
	return false;
}

int solve()
{
	int n = str.size();
	memset(dp,0,sizeof(dp));
	for(int i=0;i<=n-1;++i)dp[i][i]=0;
	
	for(int len=2;len <= n;++len)
	{//从区间长度为2开始 
		for(int i=0;i<=n-len;++i)
		{//枚举区间左端点 
			int l = i, r = i+len-1, k = i;
			int tmp=0;
			for(k=i; k<r;++k)
			dp[l][r]=max(dp[l][r],dp[l][k]+dp[k+1][r]);
		
			if(check(l,r))dp[l][r]=max(dp[l+1][r-1]+2,dp[l][r]);
		}
	}
	
	return dp[0][n-1];
}
int main()
{
	ios::sync_with_stdio(false); 
	while(true)
	{
		cin >> str;
		if(str == "end")break;
		cout << solve() << endl; 
	}
	return 0;
}

你可能感兴趣的:(程序设计思维与实践)