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

来源:互联网 发布:练级的网络手机游戏 编辑:程序博客网 时间:2024/06/06 00:46

大体题意:

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

思路:

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;}



0 0
原创粉丝点击