DOJ #200 括号序列

DOJ #200 括号序列 (区间DP)

题目描述

长度为\(n(1\leq n \leq 500)\)的由[]()四种字符组成组成的括号序列\(s\),求最长的括号子序列\(t\)的长度。

题解

考虑区间DP,设 \(f[l][r]\) 表示区间 \([l,r]\) 匹配括号子序列的最长长度。

边界条件有:

  • 单个字符:\(f[l][l] = 0\)
  • 双个字符 \(f[l][r] = match(s[l],s[r])\),其中\(match(ch_1,ch_2)\)表示两个字符是否匹配。

否则,考虑枚举一个\(k\)转移,\(f[l][r]\)这个问题可以由两个子问题\(f[l][k]\)\(f[k+1][r]\)来完成。

另外,如果\(match(s[l],s[r])\),那么也能划分成\(f[l+1][r-1]\)这个子问题。

转移方程:

  • \(f[l][r] = f[l][k] + f[k+1][r] (l \leq k < r)\)
  • 如果\(match(s[l],s[r])\),则\(f[l][r] = f[l+1][r-1]+2\)

可以采用记忆化搜索实现: 时间复杂度\(O(n^3)\)

# include <bits/stdc++.h>
using namespace std;
const int N = 505;
char s[N];
int f[N][N];
int dfs(int l,int r) {
	if (r<=l) return f[l][r]=0;
	if (r == l+1) {
		if (s[l] == '(' && s[r] == ')') return f[l][r]=2;
		if (s[l] == '[' && s[r] == ']') return f[l][r]=2;
		else return f[l][r]=0;
	}
	if (f[l][r]!=-1) return f[l][r];
	int res = 0;
	for (int i=l;i<r;i++) {
		res = max(res,dfs(l,i)+dfs(i+1,r));
	}
	if (s[l] == '(' && s[r] == ')') res=max(res,dfs(l+1,r-1)+2);
	if (s[l] == '[' && s[r] == ']') res=max(res,dfs(l+1,r-1)+2);
	return f[l][r] = res;
}
int main() {
	memset(f,-1,sizeof(f));
	int n; cin>>n;
	scanf("%s",s+1);
	printf("%d\n",dfs(1,n));
	return 0;
}
posted @ 2022-03-01 21:11  Maystern  阅读(69)  评论(0编辑  收藏  举报