本题难在输出括号序列,dp是比较简单的
dp[ i ][ j ] 存储 i~j 这段括号序列需要添加的括号数,决策有两种,对dp[ i ][ j ],
(1).若i 与j 是匹配的,只需将i+1~j-1这段变成合理的括号序列;
(2).取i~j中间的k, 使i~p 和 p+1~j 均为合理的括号序列。
状态转移方程:dp[ i ][ j ] = MIN( dp[ i + 1 ][ j - 1 ], MIN(dp[ i ][ k ]+dp[ k+1 ][ j ]) ), 其中i <= p < j.。
用记忆化搜索和string记录,时间效率低 。
测试数据的输入有空串,注意输入输出,之前cin >> str; cout << ans[0][len-1]; 提交一直OLE, 很少见的错误, 改成现在这样就A了
#include <iostream>
#include <string>
using namespace std;
const int M = 105;
char str[M];
int dp[M][M];
string ans[M][M];
int Search(int l, int r)
{
int i, min = 10000000;
if(dp[l][r] != -1) return dp[l][r];
if(l > r) return 0;
if(l == r) {
if(str[l] == '(' || str[l] == ')') ans[l][r] = "()";
else ans[l][r] = "[]";
return dp[l][r] = 1;
}
int mark = 0, tmp;
int id;
for(i = l; i < r; i++){
tmp = Search(l, i) + Search(i+1, r);
if(tmp < min){
id = i;
min = tmp;
mark = 2;
}
}
if(( str[l] == '(' && str[r] == ')' ) || ( str[l] == '[' && str[r] == ']' ) ){
tmp = Search(l+1, r-1);
if(min > tmp) {
min = tmp;
mark = 1;
}
}
if(mark == 1) ans[l][r] = str[l]+ans[l+1][r-1]+str[r];
else ans[l][r] = ans[l][id]+ans[id+1][r];
return dp[l][r] = min;
}
int main()
{
int i, j;
memset(dp, -1, sizeof(dp));
cin >> str+1;
int len = strlen(str+1);
for(i = 1; i <= len; i++)
for(j = i; j <= len; j++)
ans[i][j] = ans[j][i] = "";
Search(1, len);
cout << ans[1][len] << endl;
//system("pause");
return 0;
}
代码2:自底向上的递推,记录路径,递归输出,不用string得到答案,效率高了,0ms
#include <iostream>
using namespace std;
#define M 105
int dp[M][M], path[M][M];
char str[M];
int n;
void output(int i, int j)
{
if(i == j){
if(str[i] == '(' || str[i] == ')')
printf("()");
else printf("[]");
return;
}
if(path[i][j] == -1){
if(i+1 == j)
printf("%c%c", str[i], str[j]);
else{
printf("%c", str[i]);
output(i+1, j-1);
printf("%c", str[j]);
}
}
else{
output(i, path[i][j]);
output(path[i][j]+1, j);
}
}
int main()
{
int i, j, l, k;
gets(str);
n = strlen(str);
if(n == 0) {
printf("\n");
return 0;
}
for(l = 1; l <= n; l++){
for(i = 0; i+l-1 < n; i++){
j = i+l-1;
if(i == j) dp[i][j] = 1;
else {
dp[i][j] = INT_MAX;
if( (str[i] == '(' && str[j] == ')') || (str[i] == '[' && str[j] == ']') ){
if(i+1 == j) dp[i][j] = 0;
else {
if(dp[i][j] > dp[i+1][j-1])
dp[i][j] = dp[i+1][j-1];
}
path[i][j] = -1;
}
for(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];
path[i][j] = k;
}
}
}
}
output(0, n-1);
printf("\n");
// system("pause");
return 0;
}