POJ-1141-Brackets Sequence

POJ-1141-Brackets Sequence

传送门

这道题是区间dp~
括号匹配

题目大意:给你一个括号序列,让你构造一个长度最小的匹配的括号序列,使得给定的括号序列为构造的括号序列的子序列(注意是子序列)
文件形式读入
然后这道题用dp解决无疑了。

dp[i][j]表示第i个字符到第j个字符构成匹配的括号序列最小需要添加多少字符。
初始化部分:
dp[i + 1][i] = 0;(这个不用我说把~)
dp[i][i] = 1;单个字符最少要添加一个字符构成匹配的括号序列。
状态转移方程就是平常的区间dp思路啦~
循环:从后往前,长度从小到大
如果s[i] == s[j];
那么dp[i][j] = min(dp[i][j], dp[i + 1][j - 1]);这个地方就体现出前面为啥dp[i + 1][i]需要初始化为0的作用了。
因为如果此时j = i + 1;那么i + 1和j - 1之后就变成了交叉的情况。

如果s[i] != s[j];
那么就在这个区间找到合适的分界点维护最小值就行啦~

输出的时候递归输出噢~
如果满足s[i] == s[j];先输出s[i];递归中间一段。然后再输出s[j]:
如果不满足。我们先循环找到最适合的分界点。分别递归进去然后输出就行。

还是比较简单的~
但是我还是wa了。
因为output部分有个条件把==写成了=;
还是debug发现的。。。

代码部分:

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#define mst(a, n) memset(a, n, sizeof(a))
using namespace std;
const int N = 3e2 + 10;

string s;
int dp[N][N];

int judge(char x, char y)
{
	return x == '(' && y == ')' || x == '[' && y == ']';
}

void output(int i, int j)
{
	if (i > j)
	{
		return ;
	}
	else if (i == j)
	{
		cout << (s[i] == '(' || s[i] == ')' ? "()" : "[]");
		return ;
	}
	else if (judge(s[i], s[j]) && dp[i][j] == dp[i + 1][j - 1])
	{
		cout << s[i];
		output(i + 1, j - 1);
		cout << s[j];
		return ;
	}
	else
	{
		for (int k = i; k < j; k++)
		{
			if (dp[i][j] == dp[i][k] + dp[k + 1][j])
			{
				output(i, k);
				output(k + 1, j);
				return ;
			}
		}
	}
}

int main()
{
	while (getline(cin, s))
	{
		mst(dp, 1e9 + 10);
		int n = s.size();
		for (int i = 0; i < n; i++)
		{
			dp[i + 1][i] = 0;
			dp[i][i] = 1;
		}
		for (int i = n - 2; i >= 0; i--)
		{
			for (int j = i + 1; j < n; j++)
			{
				dp[i][j] = n;
				if (judge(s[i], s[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]);
				}
			}
		}
		output(0, n - 1);
		cout << endl;
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

娃娃酱斯密酱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值