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("");
}
}