区间dp+输出方案 poj-1141-Brackets Sequence

题目链接:

http://poj.org/problem?id=1141

题目大意:

给一个由[,],{,}组成的字符串序列,求增加最少的字符,使该序列能够匹配,并输出最后的方案。

解题思路:

区间dp.dp[i][j]表示从i~j 所需的最少的字符使之能匹配,转移的话要么是头尾匹配直接加中间,要么分成两段。

不过要输出到达路径,所以在用一个path[i][j]表示到达该路径时的选择,-1表示头尾,其他表示中间分开的位置。

递归输出路径。递归是个好东西,能够很大程度的改变顺序,特别是逆着的。

PS:这题不能用贪心直接模拟过,不一定非要每步都与前面的都匹配。

测试样例:(([[)]]  长度应为10 用模拟为12 

代码:

//递归输出结果,是个好东西
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#define eps 1e-6
#define INF 0x1f1f1f1f
#define PI acos(-1.0)
#define ll __int64
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

/*
freopen("data.in","r",stdin);
freopen("data.out","w",stdout);
*/
#define Maxn 110
char sa[Maxn];
int dp[Maxn][Maxn],path[Maxn][Maxn]; //dp[i][j]表示区间i~j内需要最少的字符数能够匹配,path[i][j]表示到达该状态是哪种情况,
//-1表示第一个和最后一个,其他表示中间的分段点,然后递归输出
//递归能够改变次序
void output(int l,int r) //递归是个好东西
{
   if(l>r)
      return ;
   if(l==r) //到达了最后
   {
      if(sa[l]=='('||sa[l]==')')
         printf("()");
      else
         printf("[]");
      return ;
   }
   if(path[l][r]==-1) //首尾,先输出开始,然后递归输出中间,最后输出结尾
   {
      putchar(sa[l]);
      output(l+1,r-1);
      putchar(sa[r]);
   }
   else
   {
      output(l,path[l][r]);//直接递归输出两部分
      output(path[l][r]+1,r);
   }
}
int main()
{
   while(gets(sa+1)) //有空串,scanf("%s"),不能读空串,然后少一个回车,会出错
   {
      int n=strlen(sa+1);
      memset(dp,0,sizeof(dp));
      for(int i=1;i<=n;i++)
         dp[i][i]=1; //一个的话只需一个就可以匹配
      for(int gap=1;gap<n;gap++) //枚举区间长度
         for(int i=1;i<=n-gap;i++) //枚举区间开始位置
         {
            int j=i+gap;
            dp[i][j]=INF;
            if((sa[i]=='['&&sa[j]==']')||(sa[i]=='('&&sa[j]==')')) //首尾情况
               if(dp[i+1][j-1]<dp[i][j])
                  dp[i][j]=dp[i+1][j-1],path[i][j]=-1;
            for(int k=i;k<j;k++) //中间分隔情况
               if(dp[i][k]+dp[k+1][j]<dp[i][j])
                  dp[i][j]=dp[i][k]+dp[k+1][j],path[i][j]=k;
         }
      output(1,n);
      putchar('\n');
   }
   return 0;
}


你可能感兴趣的:(动态规划)