【区间DP】——poj1141——括号匹配并输出括号序列

                                      Brackets Sequence

Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 29861   Accepted: 8542   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

()[()]

(转)

题意:

给出一串括号,要你补上最少的括号使这一串括号都匹配........

思路:

dp[i][j]表示从区间i到区间j使其所以括号匹配需要补上的最少括号数,

那么当出现一个括号时,

首先考虑它不与后面匹配的情况,那么需要加一个相对应的括号,让之匹配dp[i][j]=dp[i+1][j]+1;

然后再考虑,若是后面有括号可以让它匹配的情况,

那么假设i<k<=j,当s[i]=='('&&s[k]==')'的时候,

考虑动态转移,dp[i][j]=dp[i+1][k-1]+dp[k][j]-1

为什么这个动态方程减1呢,因为将与之匹配的那个括号重新计算了一次,

当s[k]==')'的时候,在计算dp[k][k]的时候,状态转移已经把这个括号自动匹配了一次,所以要减去这次匹配的........

然后就是记录路径了,

开一个二维数组a[i][j],当a[i][j]==-1的时候,表示dp[i][j]这个状态是从dp[i+1][j]推导过来的,

当a[i][j]>0的时候,表示dp[i][j]是从dp[i+1][a[i][j]-1]以及dp[k][j]这两个状态推导过来的,

那么注意到当a[i][j]!=-1的时候,就正好表示s[i]与s[a[i][j]]匹配,说明在第i个括号这个地方只需要输出它自己本身,

其他的,若是a[i][j]==-1的,都需要输出它自身以及与它自身匹配的括号.........

 

代码如下:

#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;

int dp[300][300];//dp最小需要的括号数
int a[300][300];//a[i][j]表示记录i~j的断点(a->b映射)
int b[300];//标记找到的已经匹配好的位置
char s[300];//字符串

//递归处理路径
void print(int i,int j)
{
    if(i>=j)return;

    if(a[i][j]==-1)
        print(i+1,j);

    if(a[i][j]>0)
    {
        b[i]=1;
        b[a[i][j]]=1;

        print(i+1,a[i][j]-1);
        print(a[i][j],j);
    }
}

int main()
{
    while(gets(s+1)>0)    //这里注意,有直接输入\n的情况.........
    {
        s[0]=2;
        memset(dp,0,sizeof(dp));
        memset(a,-1,sizeof(a));
        memset(b,0,sizeof(b));

        int len=strlen(s);
        len--;//保持下标统一

        for(int i=1;i<=len;i++)
            dp[i][i]=1;

        for(int i=len-1;i>=1;i--)
        {
            for(int j=i+1;j<=len;j++)
            {
                dp[i][j]=dp[i+1][j]+1;//只考虑一端的情况,另一边对称
                a[i][j]=-1;
                for(int k=i+1;k<=j;k++)
                {
                    if((s[i]=='('&&s[k]==')')||(s[i]=='['&&s[k]==']'))
                    {
                        if(dp[i][j]>dp[i+1][k-1]+dp[k][j]-1)//分段可以得到更小结果
                        {
                            dp[i][j]=dp[i+1][k-1]+dp[k][j]-1;
                            a[i][j]=k;
                        }
                    }
                }
            }
        }

        print(1,len);

        for(int i=1;i<=len;i++)
        {
            if(b[i]==1)
                printf("%c",s[i]);

            else
            {
                if(s[i]=='('||s[i]==')')
                    printf("()");
                else
                    printf("[]");
            }
        }
        printf("\n");
    }
    return 0;
}

 

posted @ 2016-07-13 21:33  琥珀川||雨露晨曦  阅读(103)  评论(0)    收藏  举报