Brackets Sequence POJ - 1141(算是区间dp入门一道不错的题?

题目大意:

用以下方式定义合法的括号字符串
1.空串是合法的
2. 如果 \(S\) 是合法的, 那么 \((S)\)\([S]\) 也都是合法的
3. 如果 \(A\)\(B\) 是合法的, 那么 \(AB\) 是一个合法的字符串.
举个栗子, 下列字符串都是合法的括号字符串:\((), [], (()), ([]), ()[], ()[()]\)
下面这些不是:\((, [, ), )(, ([)], ([(]\)
给出一个由字符'(', ')', '[', 和']'构成的字符串. 你的任务是找出一个最短的合法字符串,使得给出的字符串是这个字符串的子序列。对于字符串a1 a2 ... an, b1 b2 ... bm 当且仅当对于1 ≤ i1 < i2 < ... < in ≤ m, 使得对于所有1 ≤ j ≤ n,\(a_j\) = \(b_{i_j}\) 时, \(a_j\)\(b_i\) 的子序列
输入一个只含有'(', ')', '[', ']'字符的字符串,字符串的最大长度是100
输出一个最短的合法字符串,使得输入的字符串是输出字符串的子序列(可能有多种情况,任意一种情况都可以)

分析:

其实光是求序列里最长的合法的串的长度还是挺简单的,设 \(dp[i][j]\) 表示序列从 \(i\)\(j\) 这一段想要变成合法的括号序列所需要的最少操作次数,这里直接上状态转移方程:

\[\left\{\begin{matrix} dp[i][j] = \min(dp[i][j],dp[i + 1][j - 1])&((s[i] == '(' and s[j] == ')') &or & (s[i] == '['ands[j] == ']'))\\ dp[i][j] = min(dp[i][j],dp[i][k] + dp[k + 1][j]) \end{matrix} \right. \]

为了用递归输出方案,还要记录一下每一段内的元素是在哪里分成两截的,即左半部分能构成合法括号串,右半部分能构成合法括号串,如果为-1,则表示该段本身合法,无需分段输出,同时在输出过程中还要记得将序列补全

#include<iostream>
#include<string>
#include<cstring>
using namespace std;
const int MAXN = 2e3;
const int INF = 1e9;
string s;
int dp[MAXN][MAXN],pos[MAXN][MAXN];
void print(int i,int j){
	if(i > j)return;
	if(i == j){
		if(s[i] == '(' || s[i] == ')')cout << "()";
		else if(s[i] == '[' || s[i] == ']')cout << "[]";
		return;
	}
	if(pos[i][j] == -1){
		cout << s[i];
		print(i + 1,j - 1);
		cout << s[j];
	}
	else if(pos[i][j] != -1){
		print(i,pos[i][j]);
		print(pos[i][j] + 1,j);
	}
}
int main(){
	while(getline(cin,s)){
		if(s.size() == 0){
			puts("");
			continue;
		}
		memset(dp,0,sizeof dp);
		memset(pos,0,sizeof pos);
		for(int i = 0; i < s.size(); i++){
			dp[i][i] = 1;
		}
		for(int l = 1; l < s.size(); l++){
			for(int i = 0; i + l < s.size(); i++){
				int j = i + l;
				dp[i][j] = INF;
				if(s[i] == '(' && s[j] == ')'){
					dp[i][j] = min(dp[i][j],dp[i + 1][j - 1]);
					pos[i][j] = -1;
				} 
				else if(s[i] == '[' && s[j] == ']'){
					dp[i][j] = min(dp[i][j],dp[i + 1][j - 1]);
					pos[i][j] = -1;
				}
				for(int k = i; k < j; k++){
					if(dp[i][j] > dp[i][k] + dp[k + 1][j]){
						dp[i][j] = dp[i][k] + dp[k + 1][j];
						pos[i][j] = k;
					}
				}
			}
		}
		print(0,s.size() - 1);
		puts("");
	}
}
posted @ 2022-08-09 20:02  腾云今天首飞了吗  阅读(18)  评论(0编辑  收藏  举报