POJ 1141

Brackets Sequence

Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 35539 Accepted: 10273 Special Judge

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

()[()]

 

题意:给定一个括号序列,通过填补最少个字符,使原输入成为正规化的括号序列。

 

题解:起初考虑从左至右搜索,对于每一个左括号找到右边第一个未使用过的右括号,但这样找到的答案不满足正规化的定义,例如([)]输出仍为([)],但是不是正规化的括号序列。

由于要求解的问题是,给定一个字符串c1...cn,求出最小需要添加的字符个数(输出可以在求出最小个数后记录添加括号的位置),定义dp[i][j]为补充子串ci...cj所需添加的最小字符数,则状态转移方程为dp[i][j] = min{dp[i][k] + d[k+1][j]},检查后发现漏掉了向字符串两端扩展的定义。即dp[i][j] = dp[i+1][j-1] (c[i]与c[j]是匹配的括号对),因为匹配时并不需要添加字符。

解决了DP难题之一的状态转移方程,另一个就是如何定义循环的问题。

区间DP从小区间扩大到大区间,即区间长度为n的解依赖于长度为(n-1...1)的区间的解,所以循环首先从起点开始,逐步遍历长度为1...n的区间,最终长度为n的区间的解为最优解。回忆一下,区间dp最经典的问题:定义矩阵乘积顺序求解最小计算量。

for (int k = 1;k <= n;k++) 

    for (int i = 1;i <= n-k;i++)

        j = i+k;

        dp[i][j] = init();

        for (int mid = i+1; mid <= j;mid++)

            dp[i][j] = min(dp[i][j], dp[i][mid] + dp[mid+1][j])

对于打印,则通过pos记录额外添加括号的位置,初始pos为-1,表示不需要加括号。转移过程dp[i][j] = min{dp[i][k] + d[k+1][j]}记录下pos[i][j]=k为插入括号的位置。则打印括号序列时,pos[i][j]==-1时打印出c[i],c[j]的括号,并且继续递归打印c[i+1,...j-1]。否则当前位置没有加入括号,递归c[i,...k]和c[k+1,...j]。当i==j时,根据当前字符为(|)|[|],补全括号。

 

程序:

#include<cstring>
#include<algorithm>
#include<queue>
#include<iostream>
#include<cstdio>
#define MAXN 100010
using namespace std;

int dp[101][101];
int pos[101][101];
char c[101];

void print(int i, int j){
    if (i > j) return;
    if (i == j) {
        if (c[i] == '(' || c[i] == ')') printf("()");
        else printf("[]");
    }
    else if (pos[i][j] == -1) {
        printf("%c", c[i]);
        print(i+1, j-1);
        printf("%c", c[j]);
    }
    else {
        print(i, pos[i][j]);
        print(pos[i][j]+1, j);
    }
}

bool match(int i, int j){
    if (c[i] == '(' && c[j] == ')') return true;
    if (c[i] == '[' && c[j] == ']') return true;
    return false; 

int main(){
    while(gets(c) != NULL) {
        memset(dp, 0, sizeof(dp));
        memset(pos, -1, sizeof(pos));
        int len = strlen(c);
        for (int i = 0;i < len;i++) {
            dp[i][i] = 1;
        }
        for (int i = 1;i < len;i++){
            for (int j = 0;i + j < len;j++){
                int k = i + j;
                dp[j][k] = MAXN;
                if (match(j, k)) {
                    dp[j][k] = dp[j+1][k-1];
                    pos[j][k] = -1;
                }
                for (int r = j;r < k;r++){
                    if (dp[j][k] > dp[j][r] + dp[r+1][k]) {
                        dp[j][k] = dp[j][r] + dp[r+1][k];
                        pos[j][k] = r;
                    }
                }
            }
        }
        print(0, len-1);
        printf("\n");
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值