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

来源:互联网 发布:测颜值软件 编辑:程序博客网 时间:2024/05/16 17:07

这题绝对是经典的括号题,每次碰到括号我总是非常头疼,这次在小白的帮助下终于认真的学习了这题的解法。

这题的算法当时是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 105typedef 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;}



0 0