動態規劃的意味還是挺明顯的:如果子結構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;
}