POJ 1141 Brackets Sequence 区间dp

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
()[()]


思路:

简单区间dp,对于一段区间,分三种情况讨论:
1、这个区间被分成多块。(regular sequence算是一块)
2、整个是一块,且两边分别保留一个字符。
3、整个是一块,且只保留一边的一个字符。

代码:

#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
#include <queue>
using namespace std;
int dp[105][105],dp_cut[105][105];
char str[205];
int DP(int l,int r) {
    if(l>r) return 0;
    if(dp[l][r]!=-1) return dp[l][r];
    if(r==l) {
        return dp[l][r]=2;
    }
    int ans = 1000;
    int cut;
    if( (str[l]=='(' && str[r]==')') || (str[l]=='['&&str[r]==']') ) {
        if(2+DP(l+1,r-1)<ans) {
            ans = 2+DP(l+1,r-1);
            cut = -2;
        }
    }
    if( str[l]=='(' || str[l]=='[' ) {
        if(2+DP(l+1,r)<ans) {
            ans = 2+DP(l+1,r);
            cut = -3;
        }
    }
    if( str[r]==')' || str[r]==']' ) {
        if(2+DP(l,r-1)<ans) {
            ans = 2+DP(l,r-1);
            cut = -1;
        }
    }
    for(int m=l;m<r;m++) {
        if(DP(l,m)+DP(m+1,r)<ans) {
            ans = DP(l,m)+DP(m+1,r);
            cut = m;
        }
    }
    dp_cut[l][r] = cut;
    return dp[l][r]=ans;
}
void print_ret(int l,int r) {
    if(l>r) return;
    if(l==r) {
        if(str[l]=='['||str[l]==']') printf("[]");
        else if(str[l]=='('||str[l]==')') printf("()");
    }
    else if(dp_cut[l][r]==-2) {
        printf("%c",str[l]);
        print_ret(l+1,r-1);
        printf("%c",str[r]);
    }
    else if(dp_cut[l][r]==-3) {
        printf("%c",str[l]);
        print_ret(l+1,r);
        if(str[l]=='[') printf("]");
        else if(str[l]=='(') printf(")");
    }
    else if(dp_cut[l][r]==-1) {
        if(str[r]==']') printf("[");
        else if(str[r]==')') printf("(");
        print_ret(l,r-1);
        printf("%c",str[r]);
    }
    else {
        int m = dp_cut[l][r];
        print_ret(l,m);
        print_ret(m+1,r);
    }
}
int main() {
    while(gets(str)!=NULL) {
        memset(dp,-1,sizeof(dp));
        int len = strlen(str);
        DP(0,len-1);
        print_ret(0,len-1);
        puts("");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值