poj1141Brackets Sequence(区间dp括号匹配打印路径)

这道题困扰了我一阵,因为之前只会求最大匹配,不会打印路径,后来发现用递归可以实现,首先我们知道前面定义dp [ i ] [ j ] 为串中第 i 个到第 j 个括号的最大匹配数目

那么假如我们知道任意 i 到 j 从哪儿插入分点使得匹配添加括号最少。那么我们定义pos【i】【j】表示 i 到 j 从哪儿分开使得匹配添加括号最少,如果i和j匹配我们可以让pos【i】【j】=-1;

我们发现在我们之前更新dp [ i ] [ j ] 的时候如果中间点k使得if ( dp [ i ] [ k ] + dp [ k+1 ] [ j ] >= dp [ i ] [ j ] ) ,那么我们从k分开可以让添加的括号最少,最坑的一点是可能有空串,用scanf不行,用gets(s)当s是string型的时候不行,当用gets(s),s是char型的时候可以,当用getline(cin,s)的时候s为string的时候可以,还是太菜

#include <iostream>
#include <string.h>

using namespace std;

string s;
int pos[105][105],dp[105][105];

void show(int i,int j)
{
    if(i>j)
        return;
    if(i==j)//这里是指当递归到只剩一个的时候,如何输出
    {
        if(s[i]=='('||s[i]==')')
            cout<<"()";
        else cout<<"[]";
    }
    else
        {
            if(pos[i][j]==-1)//匹配
            {
                cout<<s[i];
                show(i+1,j-1);
                cout<<s[j];
            }
            else//更新
            {
                show(i,pos[i][j]);
                show(pos[i][j]+1,j);
            }
        }
}

int main()
{
    while(getline(cin,s))
    {
        memset(dp,0,sizeof(dp));
        memset(pos,0,sizeof(pos));
        for(int i=1;i<s.size();i++)
            for(int j=0,k=i;k<s.size();j++,k++)
            {
                if(s[j]=='('&&s[k]==')'||s[j]=='['&&s[k]==']')//如果匹配到,
                {
                    dp[j][k]=dp[j+1][k-1]+2;
                    pos[j][k]=-1;
                }
                for(int m=j;m<k;m++)
                {
                    if(dp[j][m]+dp[m+1][k]>=dp[j][k])//这里是更新
                    {
                        dp[j][k]=dp[j][m]+dp[m+1][k];
                        pos[j][k]=m;
                    }
                }
            }
        show(0,s.size()-1);
        cout<<endl;
        s.clear();

    }
    return 0;
}

你可能感兴趣的:(dp,区间DP)