题目: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; }
时间: 2024-10-11 16:21:01