题目:
http://poj.org/problem?id=1141
区间DP + 构造出DP的解
这里有两种思路都是对的:
第一种(推荐):dp[i][j] := 区间i~j最少需要加多少字符使得它符合括号匹配,然后构造出一个DP的解就好了
第二种:dp[i][j] := 区间i~j符合括号匹配的最长子序列的长度,然后在构造最长子序列的过程中标记哪些字符本身就已经匹配完毕了,然后对剩下的进行补全就好了
第一种:
#include <cstdio> #include <iostream> #include <cstring> #include <string> using namespace std; char s[105]; int dp[105][105]; int c[105][105]; void dfs(int i, int j) { if(i>j) return; if(c[i][j] == -1) { if(s[i] == '[' || s[i] == ']') printf("%s", "[]"); else printf("%s", "()"); dfs(i+1, j); } else { int k = c[i][j]; printf("%c", s[i]); dfs(i+1, k-1); printf("%c", s[k]); dfs(k+1, j); } } int main () { scanf("%s", s); int len = strlen(s); for(int step=0; step<len; step++) { for(int i=0; i+step<len; i++) { int j = i + step; dp[i][j] = dp[i+1][j]+1; c[i][j] = -1; for(int k=i+1; k<=j; k++) { if(s[i]=='(' && s[k]==')' || s[i]=='[' && s[k]==']') { if(dp[i+1][k-1]+dp[k+1][j] < dp[i][j]) { dp[i][j] = dp[i+1][k-1]+dp[k+1][j]; c[i][j] = k; } } } } } // printf("%d\n", dp[0][len-1]); dfs(0, len-1); printf("\n"); return 0; }
第二种:
#include <cstdio> #include <iostream> #include <cstring> #include <string> using namespace std; char s[105]; int dp[105][105], c[105][105]; bool vis[105]; void dfs(int i, int j) { if(i>=j) return; if(c[i][j]==-1) dfs(i+1, j); else { int k = c[i][j]; vis[i] = vis[k] = 1; dfs(i+1, k-1); dfs(k+1, j); } } int main () { scanf("%s", s); int len = strlen(s); for(int step=1; step<len; step++) { for(int i=0; i+step<len; i++) { int j = i + step; dp[i][j] = dp[i+1][j]; c[i][j] = -1; for(int k=i+1; k<=j; k++) { if(s[i]=='(' && s[k]==')' || s[i]=='[' && s[k]==']') { if(dp[i+1][k-1]+dp[k+1][j]+2 > dp[i][j]) { dp[i][j] = dp[i+1][k-1]+dp[k+1][j]+2; c[i][j] = k; } } } } } dfs(0, len-1); for(int i=0; i<len; i++) { if(vis[i]) { printf("%c", s[i]); } else { if(s[i] == '[' || s[i] == ']') printf("%s", "[]"); else printf("%s", "()"); } } printf("\n"); return 0; }
本文介绍了一种使用区间动态规划(DP)解决括号匹配问题的方法,并提供了两种实现思路。第一种方法通过计算最小添加字符数来构造解;第二种方法通过找到最长匹配子序列并标记已匹配字符,然后对剩余部分进行补全。代码示例详细说明了这两种方法的实现过程。
4206

被折叠的 条评论
为什么被折叠?



