您的位置:首页 > 产品设计 > UI/UE

例题9-10 UVA 1626 Brackets sequence (dp递推 || 记忆化搜索)

2016-10-09 22:44 435 查看
大体题意:

括号匹配问题,要求添加尽可能少的括号使得括号匹配  ,其中空括号 是匹配的,括号有[]和()两种!

思路:

dp思想:

令dp[i][j]表示字符串i位置到j位置  最少添加的括号数量!

两种方法 递推和 记忆化搜索思路是一样的,说下整体思路:

如果i和j 这两个位置能匹配的话,那么转移就是ans = min {dp[i+1][j-1]}

然后在类似于最优三角剖分的方法,在中间找一个位置!

使得ans = min{dp[i][k] + dp[k+1][j]}

无论匹配不匹配都要进行第二个转移 ,否则[][]这种情况就转移到了 ][这种情况!!

这样最终会得到  dp每个子字符串所要的括号数量!

然后是打印解!

打印直接递归好了,简单易懂!

如果打印到了边界l == r 那么就要输出一个完整的括号()或者[]

否则 如果  l 和r是匹配的,那么就  递归输出  l+1 到r-1

否则 在找中间位置 满足ans 等于dp[i][j]的,在递归输出!

注意在写递推式时,要注意枚举的方向:

这个也很好理解!

转移是转移dp[i+1][j-1]   第一维向大的方向转移 ,就要从小的位置枚举过来!保证前面的存在!

第二维同理!

不过  递推式的速度是记忆化搜索的五倍左右呢~

详细见代码:

递推式代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 100 + 10;
const int inf = 0x3f3f3f3f;
char s[maxn];
int dp[maxn][maxn];
bool ok(char a,char b){
return a == '[' && b == ']' || a == '(' && b == ')';
}
void print(int l,int r){
int ans = dp[l][r];
if (l > r)return;
if (l == r){
if (s[l] == '(' || s[l] == ')')printf("()");
else printf("[]");
return ;
}
if (ok(s[l],s[r]) && ans == dp[l+1][r-1]){
printf("%c",s[l]);
print(l+1,r-1);
printf("%c",s[r]);
return;
}
for (int k = l; k < r; ++k){
if (ans == dp[l][k] + dp[k+1][r]){
print(l,k);
print(k+1,r);
return;
}
}
}
int main(){
int n;
scanf("%d%*c",&n);
int cnt = 0;
while(n--){
gets(s);
gets(s);
int len = strlen(s);
for (int i = 0; i < len; ++i){
dp[i][i] = 1;
dp[i+1][i] = 0;
}
for (int i = len-2; i >= 0; --i){
for (int j = i+1; j < len; ++j){
dp[i][j] = 0x3f3f3f3f;
if (ok(s[i],s[j]))dp[i][j] = min(dp[i][j],dp[i+1][j-1]);
for (int k = i; k < j; ++k){
dp[i][j] = min(dp[i][j],dp[i][k] + dp[k+1][j]);
}
}
}
// printf("%d\n",dp[0][len-1]);
if (cnt++)printf("\n");
print(0,len-1);
puts("");

}

return 0;
}


记忆化搜索式代码:
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
const int maxn = 100 + 10;
int len;
int dp[maxn][maxn];
char s[maxn];

bool ok(int i,int j){
return s[i] == '(' && s[j] == ')' || s[i] == '[' && s[j] == ']';
}
int dfs(int l,int r){
int& ans = dp[l][r];
if (ans != -1)return ans;
if (l > r)return ans = 0;
if (l == r) return ans = 1;
ans = 0x3f3f3f3f;
if (ok(l,r)){
ans = min(ans,dfs(l+1,r-1));
}
for (int k = l; k < r; ++k){
ans = min(ans,dfs(l,k) + dfs(k+1,r));
}
return ans;
}
void print(int l,int r){
int ans = dp[l][r];
if (l > r)return;
if (l == r){
if (s[l] == '(' || s[l] == ')')printf("()");
else printf("[]");
return ;
}
if (ok(l,r) && ans == dp[l+1][r-1]){
printf("%c",s[l]);
print(l+1,r-1);
printf("%c",s[r]);
return;
}
for (int k = l; k < r; ++k){
if (ans == dp[l][k] + dp[k+1][r]){
print(l,k);
print(k+1,r);
return;
}
}
}
int main(){
int n;
scanf("%d%*c",&n);
int cnt = 0;
while(n--){
gets(s);
gets(s);
memset(dp,-1,sizeof dp);
len = strlen(s);
dfs(0,len-1);
// printf("%d\n",dp[0][len-1]);
if (cnt++)printf("\n");
print(0,len-1);
puts("");

}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: