◆练习题目◆◇区间动态规划◇ Brackets Sequence

区间动态规划Brackets Sequence


Description
Let us define a regular brackets sequence in the following way:

1. Empty sequence is a regular sequence. 
2. If S is a regular sequence, then (S) and [S] are both regular sequences. 
3. If A and B are regular sequences, then AB is a regular sequence. 

For example, all of the following sequences of characters are regular brackets sequences:

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

And all of the following character sequences are not:

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

Some sequence of characters ‘(‘, ‘)’, ‘[‘, and ‘]’ is given. You are to find the shortest possible regular brackets sequence, that contains the given character sequence as a subsequence. Here, a string a1 a2 … an is called a subsequence of the string b1 b2 … bm, if there exist such indices 1 = i1 < i2 < … < in = m, that aj = bij for all 1 = j = n.
Input
The input file contains at most 100 brackets (characters ‘(‘, ‘)’, ‘[’ and ‘]’) that are situated on a single line without any other characters among them.
Output
Write to the output file a single line that contains some regular brackets sequence that has the minimal possible length and contains the given sequence as a subsequence.
Sample Input

([(]

Sample Output

()[()]

题目大意
给出一个括号序列(最长长度100),包含 “[]” 和 “()” 。插入最少的括号,使序列中的括号全部匹配,注意——”[(])” 不认为是匹配的。输出这个序列,题目设置有 Special judge,可输出任何一个答案。


题目解析
对于任意一个区间DP,它的状态定义都是:

g[x][y]表示在原序列中第x到第y个元素的答案;
或者,g[x][y]表示在原序列中从第x个元素开始的y个元素的答案;

然后便是状态转移方程式,由于数组g无法同时保存字符串,因此只能保存最少添加的括号数量。分2种情况——

  1. 当前第x个字符与第y个字符匹配
  2. 当前第x个字符与第y个字符不匹配

通过假设:

设A、B都为完全匹配的括号序列,则AB和 (A)、(B)、[A]、[B] 也是完全匹配的括号序列。

我们可以证出针对情况1的 g[x][y] 应该等于 g[x+1][y-1] ,即忽略当前的位置计算把中间的序列变成完全匹配的括号序列需要多少次。但是这并不意味着遇到情况1时就不考虑情况2,给出一个简单的反例—— “()()”。若只考虑情况1,则针对 “)(“就会得到2,但是正确答案是0。接下来就考虑情况2,也就是 AB 的情况。我们需要把原串变成 AB 的形式,也就是在某一个点分为2份,因此枚举k,分割为 x~k 和 k+1~y 的两个区间
最后是设置边界,当 x==y 时,也就是只剩下一个字符时(例如”(” 和 “]”),只能添加一个括号,即返回1。
输出方案则是通过递归,详见程序(不要说作者懒)。


程序样例

/*Lucky_Glass*/
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
string s;
bool f[105][105];
int g[105][105];
int G(int x,int y)
{
    if(x>y) return 0;
    if(x==y) return g[x][y]=1;
    if(f[x][y]) return g[x][y];
    f[x][y]=true;
    if((s[x]=='(' && s[y]==')') || (s[x]=='[' && s[y]==']')) g[x][y]=G(x+1,y-1);
    else g[x][y]=y-x+5;
    for(int i=x;i<y;i++)
        g[x][y]=min(g[x][y],G(x,i)+G(i+1,y));
    return g[x][y];
}
void VJudge(int x,int y)
{
    if(x>y) return;
    if(x==y)
    {
        if(s[x]=='(' || s[y]==')') printf("()");
        else printf("[]");
        return;
    }
    for(int i=x;i<y;i++)
        if(g[x][y]==g[x][i]+g[i+1][y])
        {
            VJudge(x,i),VJudge(i+1,y);
            return ;
        }
    if(g[x][y]==g[x+1][y-1] && (s[x]=='(' && s[y]==')') || (s[x]=='[' && s[y]==']')) printf("%c",s[x]),VJudge(x+1,y-1),printf("%c",s[y]);
}
int main()
{
    cin>>s;
    G(0,(int)s.length()-1);
    VJudge(0,(int)s.length()-1);
    printf("\n");
    return 0;
}

The End

Thanks for reading!

-Lucky_Glass

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值