本题难在输出括号序列,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; }