poj 1141Brackets Sequence[区间dp]

时间:2022-12-18 08:17:11

原题链接poj 1141 Brackets Sequence

由于对括号匹配的时候不只有一种方案,而本题要求要找最少的那种匹配方案,故可以用区间dp;

dp[i][j]表示从i到j之间为了匹配所需要的最少添加数。

状态转移方程 dp[i][j]=dp[i+1][j-1] (s[i]==s[j]);dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j])(i<=k<j);

又因为本题要输出匹配后的串,故需要把转移的路径记录下来,用pos[i][j]记录使dp[i][j]取最小值时的分开地方,

即上次动态转移方程中的最优的k值。然后递归输出。。。


参考代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 105
#define inf 0x7f7f7f7f
using namespace std;
char s[N];
int dp[N][N];
int pos[N][N];
char match(int c)
{
    if(c=='(')return ')';
    else if(c=='[')return ']';
    else return 'x';
}
void print(int l,int r)
{
    if(dp[l][r]==0)
    {
        for(int i=l; i<=r; i++)
            printf("%c",s[i]);
        return;
    }
    if(l==r)
    {
        if(s[l]=='('||s[l]==')')printf("()");
        else if(s[l]=='['||s[l]==']')printf("[]");
        return ;
    }
    if(pos[l][r]==-1)
    {
        printf("%c",s[l]);
        print(l+1,r-1);
        printf("%c",s[r]);
        return ;
    }
    else
    {
        print(l,pos[l][r]);
        print(pos[l][r]+1,r);
    }
    return ;
}
int main()
{
    //freopen("in.txt","r",stdin);
    scanf("%s",s);
    memset(dp,0,sizeof(dp));
    memset(pos,0,sizeof(pos));
    int n=strlen(s);
    for(int i=0; i<n; i++)
    {
        dp[i][i]=1;
    }
    for(int l=1; l<n; l++)
        for(int i=0; i+l<n; i++)
        {
            int j=i+l;
            dp[i][j]=inf;
            if(match(s[i])==s[j])
            {
                dp[i][j]=dp[i+1][j-1];
                pos[i][j]=-1;
            }
            for(int k=i; k<j; k++)
                if(dp[i][j]>dp[i][k]+dp[k+1][j])
                {
                    dp[i][j]=dp[i][k]+dp[k+1][j];
                    pos[i][j]=k;
                }
        }
    print(0,n-1);
    printf("\n");
    return 0;
}