题意:
定义合法串为(),[]以及他们的并列组合如()[],()(),或嵌套组合如([]),(())。 其实正常理解就好~
然后给你一个串,让你求出把它改对后的最短合法串。
类型:
DP动态规划
思路:
当我拿到一个字符i, 那么在一种最优结果中,它只有这么两种结果:要么和某个字符匹配,要么不匹配。
定义状态:
dp[i][j]为 i到j的子串中 所能做到的最大匹配数符号数。
最大匹配符号数说明:如(([))]] 如果这么匹配(([))]] 数量为2, 而这样匹配 (([))]] 数量为4。易知后者也是最大的,所以这个子串最大匹配符号数为4.
状态转移:
首先特判:若i所在字符与j所在字符能匹配(() 或 []) 那么尝试匹配这两个字符
ans = dp[i+1][j-1] + 2;
然后,不匹配ij两个字符,尝试把字符串分成两段(i,i+k) (i+k+1, j)(那么这里其实是假想让i字符与当中第i+k个字符匹配,当k=0时其实就是不匹配。k从0到j-i-1)
代码:
#include <cstdio> #include <cstdlib> #include <cstring> //18:09 char str[200]; int dp[120][120]; int flag[200][200]; int chooes[200]; int dfs(int i, int j) { if (dp[i][j] != -1) return dp[i][j]; if (j - i < 1) return dp[i][j] = 0; int &ans = dp[i][j]; if (str[i] == '(' && str[j] == ')' || str[i] == '[' && str[j] == ']') { ans = dfs(i+1, j-1) + 2; flag[i][j] = -99; } int k; for (k = 0; k < j-i; k++) { if (ans < dfs(i,i+k) + dfs(i+k+1, j)) { ans = dfs(i,i+k) + dfs(i+k+1, j); flag[i][j] = k; } } return ans; } int main() { //while (scanf("%s", str+1) != EOF) scanf("%s", str+1); { memset(dp, -1, sizeof(dp)); memset(chooes, 0, sizeof(chooes)); int len = strlen(str+1); dfs(1, len); // Use stack to find which is choosen int i = 1; int j = len; int si[200], sj[200]; int pi = 0, pj = 0; si[pi++] = 1; sj[pj++] = len; while (pj) { i = si[--pi]; j = sj[--pj]; if (flag[i][j] == -99) { //Choosen chooes[i] = chooes[j] = 1; si[pi++] = i+1; sj[pj++] = j-1; } else if (j-i>=1) { si[pi++] = i; sj[pj++] = i+flag[i][j]; si[pi++] = i+flag[i][j]+1; sj[pj++] = j; } } for (i = 1; i <= len; i++) { if (chooes[i]) putchar(str[i]); // Those who is choosen needn't to fix else { switch (str[i]) { case '(': case ')': printf("()");break; case '[': case ']': printf("[]");break; } } } puts(""); } return 0; }