Brackets sequence
定义如下正规括号序列:
①空序列是正规括号序列
②如果S是正规括号序列,那么(S)和[S]也是正规括号序列
③如果A和B都是正规括号序列,那么AB也是正规括号序列。
输入一个长度不超过100的,由"("、")"、"["、"]"构成的序列,添加尽量少的括号,得到一个规则序列。如有多解,任意输出一个序列即可。
dp[i][j]表示从i到j需要加多少括号,边界为i==j时,要加一个。
由题目定义②③可知,有两种转移情况:
1、两边是()或[],那么可由dp[i+1][j-1]转移而来。
2、由A和B转移而来,其中A和B是已经处理完的两部分。(枚举断点)
∵如果j-i=1时满足条件1,那么i+1>j-1
∴要定义另一个边界dp[i+1][i]=0。
输出用递归输出,也按这两个转移条件来。
✳本题最后一行不能多输出空格,而且读入可能为空字符串,所以不能用cin和scanf
※UVA上提交的代码如果格式错误是WA,而不是PE
递推代码(420ms)
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define mem(a,b) memset(a,b,sizeof(a));
//#define int ll
using namespace std;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int maxn = 110;
char a[maxn];
int n;
int dp[maxn][maxn];
void print(int left, int right)
{
if (left > right)
return;
if (left == right)
{
if (a[left] == '(' || a[left] == ')')
printf("()");
else
printf("[]");
return;
}
if (dp[left][right] == dp[left + 1][right - 1] && ((a[left] == '('&&a[right] == ')') || (a[left] == '['&&a[right] == ']')))
{
putchar(a[left]);
print(left + 1, right - 1);
putchar(a[right]);
return;
}
for (int i = left; i < right; i++)
{
if (dp[left][i] + dp[i + 1][right] == dp[left][right])
{
print(left, i);
print(i + 1, right);
return;
}
}
}
int main()
{
//freopen("C:/Users/12237/Desktop/text.in", "r", stdin);
//freopen("C:/Users/12237/Desktop/text.out", "w", stdout);
int t;
scanf("%d", &t);
getchar();
while (t--)
{
getchar();
int cnt = 0;
while (true)
{
char temp = getchar();
if (temp == '\n')
break;
cnt++;
a[cnt] = temp;
}
n = cnt;
if (cnt == 0)
{
puts("");
}
else
{
mem(dp, inf);
for (int i = 1; i <= n; i++)
{
dp[i][i] = 1;
dp[i + 1][i] = 0;
}//dp[i][j]表示从i到j至少要加几个括号
for (int j = 2; j <= n; j++)
{
for (int i = j - 1; i >= 1; i--)
{
//当i和j匹配
if ((a[i] == '('&&a[j] == ')') || (a[i] == '['&&a[j] == ']'))
{
dp[i][j] = min(dp[i][j], dp[i + 1][j - 1]);
}
for (int k = i; k < j; k++)//区间划分为k和k+1之间
{
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j]);
}
}
}
print(1, n);
putchar('\n');
}
if(t!=0)
putchar('\n');
}
}
记忆化搜索代码(1250ms)
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define mem(a,b) memset(a,b,sizeof(a));
//#define int ll
using namespace std;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int maxn = 110;
char a[maxn];
int n;
int dp[maxn][maxn];
int dfs(int left, int right)
{
if (dp[left][right] != inf)
return dp[left][right];
if (left == right)
return dp[left][right] = 1;
if (left == right + 1)
return dp[left][right] = 0;
int temp = inf;
if ((a[left] == '('&&a[right] == ')') || (a[left] == '['&&a[right] == ']'))
temp = min(temp, dfs(left + 1, right - 1));
for (int k = left; k < right; k++)
{
temp = min(temp, dfs(left, k) + dfs(k + 1, right));
}
return dp[left][right] = min(dp[left][right], temp);
}
void print(int left, int right)
{
if (left > right)
return;
if (left == right)
{
if (a[left] == '(' || a[left] == ')')
printf("()");
else
printf("[]");
return;
}
if (dp[left][right] == dp[left + 1][right - 1] && ((a[left] == '('&&a[right] == ')') || (a[left] == '['&&a[right] == ']')))
{
putchar(a[left]);
print(left + 1, right - 1);
putchar(a[right]);
return;
}
for (int i = left; i < right; i++)
{
if (dp[left][i] + dp[i + 1][right] == dp[left][right])
{
print(left, i);
print(i + 1, right);
return;
}
}
}
int main()
{
//freopen("C:/Users/12237/Desktop/text.in", "r", stdin);
//freopen("C:/Users/12237/Desktop/text.out", "w", stdout);
int t;
scanf("%d", &t);
getchar();
while (t--)
{
getchar();
int cnt = 0;
while (true)
{
char temp = getchar();
if (temp == '\n')
break;
cnt++;
a[cnt] = temp;
}
n = cnt;
if (cnt == 0)
{
puts("");
}
else
{
mem(dp, inf);
dfs(1, n);
print(1, n);
putchar('\n');
}
if (t != 0)
putchar('\n');
}
}