#UVA1626#Brackets sequence(括号序列---石子归并类Dp)

来源:互联网 发布:网络暴力相关事件 编辑:程序博客网 时间:2024/06/06 00:54

题意:

给出T个字符串,仅由 '('  ')'  '['  ']' 四种 字符组成,其中 ’()‘ '[]'为合法,'()[]'  '([])' '[()]' 均为合法,而’[(])‘ '[)' 则为不合法状态

求最少添加多少个字符,使得字符串合法,输出合法的其中一种方案。(原始字符串字符不多于100个)


第一行为字符串数量。


样例输入:

1

([(]


样例输出:

()[()]


这题让人很容易想起之前做过的一道叫“剔除多余括号”的分治题,

当时是看外围那一圈是否可以去掉,

然后这题我就想分成两种情况,

第一,如果外围匹配,那么递归到里面

第二,长度大于一,无论是否匹配,都枚举中间分界点k,将字符串分为两段,分别递归求解

边界条件是长度为空时返回,为1时判断后匹配返回,用的是string类型,比较方便。

其实这个想法就像搜索一样,去把所有的方案都试过了,很显然会TLE,事实上也的确如此。


正解Dp:

令Dp[ i ][ j ]表示从 i 到 j 的字符串中需要添加括号的数量,

对于S[i]是否等于S[j],会产生同上分析的两种情况。

Dp[ i ][ j ] = min(Dp[ i ][ k ] + Dp[ k + 1 ][ j ]);

当S[i] == S[j]时,有Dp[ i ][ j ] = min(Dp[ i + 1 ][ j - 1 ], Dp[ i ][ j ]);

输出的时候同样分类讨论,根据Dp[ i ][ j ]中的值辅助输出结果,代码还是非常好懂的。


先给出TLE代码:

StatusTime limit exceededLength1380LangC++ 5.3.0Submitted2017-07-18 20:10:32Shared

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#include<map>using namespace std;string X;string Table[4] = {"(", ")", "[", "]"};map<string, string>MAP;string Work(string S){    if(MAP.count(S))return MAP[S];    if(S.size() == 0) return string("");    if(S.size() == 1){        if(S == Table[0])   return S + Table[1];        else if(S == Table[1])   return  Table[0] + S;        else if(S == Table[2])   return  S + Table[3];        else return  Table[2] + S;    }    int len = S.size();    string rt, p;    if((S[0] == '[' && S[len - 1] == ']') || (S[0] == '(' && S[len - 1] == ')'))        rt = S[0] + Work(S.substr(1, len - 2)) + S[len - 1];    if(len >= 2)        for(int i = 1; i < len; ++ i){//S = ")("            string lsub = S.substr(0, i);            string l = Work(lsub);//"()"            if(MAP.count(lsub) == 0)                MAP[lsub] = l;            string rsub = S.substr(i, len - i);            string r = Work(rsub);//"()"            if(MAP.count(rsub) == 0)                MAP[rsub] = r;            p = l + r;//"()()"            if(p.size() < rt.size() || rt.size() == 0)                rt = p;        }    return rt;}int main(){    int T;    scanf("%d", &T);    while(T --){        cin >> X;        string rt = Work(X);        cout << rt << endl;    }    return 0;}



正解

Code:

StatusAcceptedTime390msLength1641LangC++11 5.3.0Submitted2017-07-17 19:48:59Shared

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<vector>#include<cmath>#include<queue>#include<algorithm>using namespace std;const int Max = 100;const int INF = 0x3f3f3f3f;int N;char S[Max + 5];int Dp[Max + 5][Max + 5];bool Match(int a, int b){    if((S[a] == '(' && S[b] == ')') || (S[a] == '[' && S[b] == ']'))        return 1;    return 0;}void Print(int l, int r){    if(l > r)   return ;    if(l == r){        if(S[l] == '(' || S[l] == ')')  printf("()");        else printf("[]");        return ;    }    if(Match(l, r) && Dp[l][r] == Dp[l + 1][r - 1]){        printf("%c", S[l]);        Print(l + 1, r - 1);        printf("%c", S[r]);        return ;    }    for(int k = l; k < r; ++ k) if(Dp[l][r] == Dp[l][k] + Dp[k + 1][r]){        Print(l, k);        Print(k + 1, r);        return ;    }}int main(){    int T, flg = 0;    scanf("%d", &T);    getchar();    while(T --){        gets(S);        gets(S);        N = strlen(S);        if(! N){            if(flg ++)  putchar(10);            putchar(10);            continue;        }        for(int i = 0; i < N; ++ i)            Dp[i][i] = 1;        for(int i = N - 1; i >= 0; -- i){            for(int j = i + 1; j < N; ++ j){                Dp[i][j] = INF;                if(Match(i, j))                    Dp[i][j] = min(Dp[i][j], Dp[i + 1][j - 1]);                for(int k = i; k < j; ++ k)                    Dp[i][j] = min(Dp[i][j], Dp[i][k] + Dp[k + 1][j]);            }        }        if(flg ++)  putchar(10);        Print(0, N - 1);        putchar(10);    }    return 0;}