UVA1626Brackets sequence(区间DP--括号匹配+递归打印)

VJ传送门:https://cn.vjudge.net/problem/UVA-1626


题目描述:

定义合法的括号序列如下:

1 空序列是一个合法的序列

2 如果S是合法的序列,则(S)和[S]也是合法的序列

3 如果A和B是合法的序列,则AB也是合法的序列

例如:下面的都是合法的括号序列

(),  [],  (()),  ([]),  ()[],  ()[()]

下面的都是非法的括号序列

(,  [,  ),  )(,  ([)],  ([(] 

给定一个由'(',  ')',  '[', 和 ']' 组成的序列,找出以该序列为子序列的最短合法序列。


思路:

i-j表示的是一条序列的开始和结束,dp[ i ][ j ]表示子串s[ i~j ] 需要添加的数量。

思想是不断分割小区间,当出现(X)时,应该转移到x,即从dp(i,j)转移到dp(i+1,j-1)

如果为单个字符,则dp[ i ][ j ] = 1;(i == j) 

打印:算出最优的地方 1、如果可以直接往里转移,则 dp[ i ][ j ] == dp[ i+1 ][ j-1 ];把s[i]和s[j]打印了,再向里递归print(i+1, j-1);

                                    2、s[i]!=s[j],则直接去找i-j之间的最优点k进行切分,然后递归


收获:递归打印出dp结果的最优解!新技能get!

另:输入输出略坑。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
int dp[105][105], n;
char s[105];
bool match(char p, char q)
{
    if(p == '(' && q == ')')
        return true;
    if(p == '[' && q == ']')
        return true;
    return false;
}
void getdp()
{
    for(int i = 0; i < n; i++)
    {
        dp[i+1][i] = 0;
        dp[i][i] = 1;
    }
    for(int i = n - 2; i >= 0; i--)
        for(int j = i+1; j < n; j++)
        {
            dp[i][j] = n;
            if(match(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]);
        }
}
void print(int i, int j)
{
    if(i > j)
        return ;
    if(i == j)
    {
        if(s[i] == '(' || s[i] == ')')
            printf("()");
        else
            printf("[]");
        return ;
    }
    int ans = dp[i][j];
    if(match(s[i], s[j]) && ans == dp[i+1][j-1])
    {
        printf("%c", s[i]);
        print(i+1, j-1);
        printf("%c", s[j]);
        return ;
    }
    for(int k = i; k < j; k++)
    {
        if(ans == dp[i][k] + dp[k+1][j])
        {
            print(i, k);
            print(k+1, j);
            return ;
        }
    }
}
int main()
{
    int T;
    scanf("%d", &T);
    getchar();
    while(T--)
    {
        gets(s);
        gets(s);
        n = strlen(s);
        getdp();
        print(0, n-1);
        puts("");
        if(T)
            puts("");
    }
    return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值