动态规划的意味还是挺明显的:如果子结构A、B都ok,则AB也ok。如果Aok,则(A)、[A]也ok。
那么对于一个序列,我们只要扫描他所有的子结构,取子结构中dp值最小的就好了。边界条件是1、单独一个元素,这时因为无法配对,一定要加上另外一半的括号,因此dp值为1;2、一对配好对的括号,dp值为0。
打印解:再次用到了Ideal Path的方法。因为只用打印任意一组解,找到第一个dp值相同的一对子结构就可以递归然后return了。这个return不能忘记,否则会打印出多组解掺杂在一起。
UVa第一百题,再接再厉!
Run Time: 0.985s
#define UVa "LT9-10.1626.cpp" //
char fileIn[30] = UVa, fileOut[30] = UVa;
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
//Global Variables. Reset upon Each Case!
const int maxn = 100 + 10;
int d[maxn][maxn];
char dummy, s[maxn];
/
int match(char a, char b) {
if( (a == '(' && b == ')') || (a == '[' && b == ']')) return 1;
return 0;
}
void print_ans(int i, int j) {
if(i == j) printf("%s", (s[i] == '(' || s[i] == ')')?"()":"[]");
else {
for(int k = i; k < j; k ++) {
if(d[i][j] == d[i][k] + d[k+1][j]){
print_ans(i, k);
print_ans(k+1, j);
return;
}
}
if(d[i][j] == d[i+1][j-1]) {
if(i == j-1) printf("%c%c", s[i], s[j]);
else {
printf("%c", s[i]);
print_ans(i+1, j-1);
printf("%c", s[j]);
}
return;
}
}
}
int main() {
int kase;
scanf("%d", &kase);
gets(s);
while(kase--) {
gets(s);
gets(s);
int n = strlen(s);
if(n) {
for(int len = 0; len < n; len ++) {
for(int i = 0; i+len < n; i ++) {
int j = i + len;
if(len == 0) d[i][j] = 1; //single bracket.
else {
d[i][j] = d[i][i] + d[i+1][j];
for(int k = i + 1; k < j; k ++)
d[i][j] = min(d[i][j], d[i][k] + d[k+1][j]);
if(match(s[i],s[j])) {
if(i == j - 1) d[i][j] = 0;
else d[i][j] = min(d[i][j], d[i+1][j-1]);
}
}
}
}
print_ans(0, n-1);
}
printf("\n");
if(kase) printf("\n");
}
return 0;
}