题目:http://poj.org/problem?id=1141
这是一道区间dp
看到题的时候第一时间想到的是用栈储存左括号,遇到匹配的右括号就弹出栈顶元素,用一个string字符串储存遍历的结果,一提交就是wa,,看到题解是用区间dp,,区间dp也学了几个了,还是不会用。。。
好了开始分析问题
首先是dp[i][i] = 1
这种情况就是只有单个字符的时候最少都需要另一个括号匹配
其次是当j = i+1且s[i]与s[j]匹配,这时候从i到j就不需要另外的括号匹配,所以s[i][j] = s[i+][j-1] = 0;
这时候你最好就画个表看看,比如s[1]和s[2]匹配那么dp[1][2] = dp[2][1],又比如s[2]和s[3]匹配那么就是dp[2][3] = d[3][2] = 0,所以就可以得出主对角线下面这个三角形全都要赋值为0
其他情况初始化为dp[i][j] = s.size();
因为其他情况就是不匹配的情况,不匹配的情况可以是所有的括号都是左括号,这样我们就需要同样多的右括号,所有最大需要添加的括号就是s.zize();
向其他博客学习了下这个算法,再根据自己的理解写了篇笔记,我真菜~~
以下ac代码:
#include <iostream>
#include <string>
using namespace std;
string str;
int dp[100][100];
bool Match(int i, int j) {
return (str[i] == '(' && str[j] == ')') || (str[i] == '[' && str[j] == ']');
}
void DP() {
int i,j,k;
int len = str.size();
for (i = 0; i < str.size(); i++) {
dp[i][i] = 1;
}
for(i = len - 2;i >= 0;i--)
for (j = i + 1; j < len; j++) {
dp[i][j] = len;
if (Match(i, j)) {
dp[i][j] = min(dp[i][j], dp[i + 1][j - 1]);
}
for (k = i; k < j; k++) {
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j]);
}
}
}
void output(int i,int j) { //递归输出
if (i > j) return;
else if (i == j) {
cout << ((str[i] == '(' || str[i] == ')') ? "()" : "[]");
return;
}
else if (Match(i, j) && dp[i][j] == dp[i + 1][j - 1]) {
cout << str[i];
output(i + 1, j - 1);
cout << str[j];
}
else {
for (int k = i; k < j; k++) {
if (dp[i][j] == dp[i][k] + dp[k + 1][j]) {
output(i, k);
output(k + 1, j);
return;
}
}
}
}
int main() {
cin >> str;
if (str.size() == 0) { //这里我把空串先给判断了
cout << "" << endl;
return 0;
}
DP();
output(0,str.size()-1);
return 0;
}