您的位置:首页 > 产品设计 > UI/UE

***UVa-1626 Brackets sequence ACM解题报告(巧妙地递推+打印)经典的括号 dp题

2015-02-06 23:56 253 查看
这题绝对是经典的括号题,每次碰到括号我总是非常头疼,这次在小白的帮助下终于认真的学习了这题的解法。

这题的算法当时是dp,转移过程比较复杂,用d数组记录当前情况需要添加的括号数,分析d(i,j)的状态,有如下两种:

1.如果s[i]和s[j]配对,那么d(i,j)=d(i+1,j-1);

2.如果字符串有2个及以上的字符,可以将原本的字符串分为两个,转移为d(i,j)=d(i,k)+d(k+1,j);(配对的情况下也要考虑这种情况,因为1的转移未必是最优解,比如[][],如果只用1转移,就是][,要添2个括号,所以要进行2的转移)。

这题最坑爹的莫过于输入输出,第一个数下面要一个空行,每个input之间要一个空行,每个output之间要一个空行。

我学习小白书用的是递推的方法,倒叙枚举i,递推往往是比递归快,我要尽快学会写递推式子。

#include<iostream>
#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<stack>
using namespace std;
#define MAX 105
typedef long long LL;
const double pi=3.141592653589793;
const int INF=1e9;
const double inf=1e20;
int d[105][105];//记录i-j之间需要添多少个括号。
char s[105];
bool match(char a,char b)
{
    if(a=='('&&b==')') return true;
    else if(a=='['&&b==']') return true;
    return false;
}
void print(int i,int j)
{
    if(i>j) return ;
    if(i==j)
    {
        if(s[i]=='('||s[i]==')') printf("()");
        else if(s[i]=='['||s[i]==']') printf("[]");
        return ;
    }
    int ans=d[i][j];
    if(match(s[i],s[j])&&ans==d[i+1][j-1])
    {
        printf("%c",s[i]);
        print(i+1,j-1);
        printf("%c",s[j]);
        return;//记得结束
    }
    for(int k=i; k<j; k++)
    {
        if(ans==d[i][k]+d[k+1][j])
        {
            print(i,k);
            print(k+1,j);
            return ;//这里一定要记得return
        }
    }
}
int main()
{
    int n;
    scanf("%d",&n);
    getchar();
    while(n--)
    {
        int count=0;
        char c;
        memset(d,0,sizeof(d));//每个input前有一个空行
        memset(s,0,sizeof(s));//初始化s数组不能忘记
        gets(s);
        gets(s);
        int len=strlen(s);//长度是len,一开始我写错写了n,错了好久。
        for(int i=0; i<len; i++) d[i][i]=1;
        for(int i=len-2; i>=0; i--)
        {
            for(int j=i+1; j<len; j++)
            {
                d[i][j]=INF;
                if(match(s[i],s[j])) d[i][j]=min(d[i][j],d[i+1][j-1]);//两边可以配对,需要
                for(int k=i; k<j; k++) d[i][j]=min(d[i][j],d[i][k]+d[k+1][j]);//满足上面那个未必就是最优解,比如[][],
                                                                             //所以一定要尝试第二种把这个字符串分为两个字符串
            }
        }
        print(0,len-1);
        printf("\n");
        if(n) printf("\n");//坑死人不偿命啊,每个output之间还有个空行T_T,论认真读题的重要性
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: