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

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

2017-07-17 19:51 267 查看
题意:

给出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 exceeded
Length1380
LangC++ 5.3.0
Submitted2017-07-18 20:10:32
Shared
#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:

StatusAccepted
Time390ms
Length1641
LangC++11 5.3.0
Submitted2017-07-17 19:48:59
Shared
#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] == ']'))
ret
4000
urn 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: