Brackets sequence UVA - 1626

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');
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值