#605 (Div. 3)F. Two Bracket Sequences(bfs+dp)

题目描述

You are given two bracket sequences (not necessarily regular) s and t consisting only of characters ‘(’ and ‘)’. You want to construct the shortest regular bracket sequence that contains both given bracket sequences as subsequences (not necessarily contiguous).
Recall what is the regular bracket sequence:
() is the regular bracket sequence;
if S is the regular bracket sequence, then (S) is a regular bracket sequence;
if S and T regular bracket sequences, then ST (concatenation of S and T) is a regular bracket sequence.
Recall that the subsequence of the string s is such string t that can be obtained from s by removing some (possibly, zero) amount of characters. For example, “coder”, “force”, “cf” and “cores” are subsequences of “codeforces”, but “fed” and “z” are not.

Input

The first line of the input contains one bracket sequence s consisting of no more than 200 characters ‘(’ and ‘)’.
The second line of the input contains one bracket sequence t consisting of no more than 200 characters ‘(’ and ‘)’.

Output

Print one line — the shortest regular bracket sequence that contains both given bracket sequences as subsequences (not necessarily contiguous). If there are several answers, you can print any.

Examples

inputCopy
(())(()
()))()
outputCopy
(())()()
inputCopy
)
((
outputCopy
(())
inputCopy
)
)))
outputCopy
((()))
inputCopy
())
(()(()(()(
outputCopy
(()()()(()()))

题目大意

给你一个只包含左括号和右括号的序列s和t ,要求构造一个括号序列,使得所有括号匹配且s和t都是这个序列的子序列。

题目分析
  1. 状态表示f[i][j][k] //a串匹配到了第i个位置,b串匹配到了第j个位置,答案序列中左括号比右括号多k个(为了保证答案序列合法,只能是左括号比右括号多)时得到的答案序列的长度
  2. 状态计算:可以利用bfs来进行遍历和计算
    1)a[i]=='(' , b[j] =='(' //此时只放入一个'('即可,即 f[i][j][k]=f[i-1][j-1][k-1]+1
    但为了保证答案序列的合法性,还需放入一个')',即 f[i][j][k]=f[i][j][k+1]+1
    2)a[i]==')' , b[j] =='(' //需要放入一个最括号和右括号,这样正好能维持平衡,所以不需要再多见括号了。f[i][j][k]=f[i-1][j][k+1]+1,f[i][j][k]=f[i][j-1][k-1]+1
    3)a[i]=='(' , b[j] ==')' //需要放入一个最括号和右括号,这样正好能维持平衡,所以不需要再多见括号了。f[i][j][k]=f[i-1][j][k-1]+1,f[i][j][k]=f[i][j-1][k+1]+1
    4)a[i]==')' , b[j] ==')' //此时只放入一个')'即可,即 f[i][j][k]=f[i-1][j-1][k+1]+1
    但为了保证答案序列的合法性,还需放入一个'(',即 f[i][j][k]=f[i][j][k-1]+1

最后答案为f[n][m][0]。

代码如下
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <stack>
#include <map>
#include <queue>
#include <vector>
#include <set>
#include <algorithm>
#include <iomanip>
#define LL long long
using namespace std;
const int N=205,INF=0x3f3f3f3f;
struct Node{	//dp中的三个维度:x(i),y(j),z(k),c(该位置是左括号还是右括号)
	int x,y,z;
	char c;
	Node(int xx=0,int yy=0,int zz=0,char cc=0)
		:x(xx),y(yy),z(zz),c(cc)
	{}
}p[N][N][N];	//记录dp的路径
string a,b;
int f[N][N][N];	//dp数组
vector<char> ans;	//答案串
void bfs()		//注:dfs的dp和正常的dp计算的顺序不太一样
{
	memset(f,0x3f,sizeof f);	//初始化
	queue<Node> q;
	q.push(Node());		//将开始位置(0,0,0)放入队列
	f[0][0][0]=0;
	while(q.size())
	{
		Node t=q.front();
		q.pop();
		//为了保证序列的合法性,我们每次都要放入一对括号
		int x=t.x+(t.x<a.size()&&a[t.x]=='(');	//dp过程
		int y=t.y+(t.y<b.size()&&b[t.y]=='(');
		int z=t.z+1;
		if(z>=0&&z<=200&&f[x][y][z]>=INF)	//因为bfs,所以能保证第一次放入的即为最小值
		{
			f[x][y][z]=f[t.x][t.y][t.z]+1;	//dp过程
			p[x][y][z]=Node(t.x,t.y,t.z,'(');	//保存路径
			q.push(Node(x,y,z));	//将该位置再放入队列中
		}
		
		x=t.x+(t.x<a.size()&&a[t.x]==')');	//同上
		y=t.y+(t.y<b.size()&&b[t.y]==')');
		z=t.z-1;
		if(z>=0&&z<=200&&f[x][y][z]>=INF)
		{
			f[x][y][z]=f[t.x][t.y][t.z]+1;
			p[x][y][z]=Node(t.x,t.y,t.z,')');
			q.push(Node(x,y,z));
		}
	}
}

int main()
{
	cin>>a>>b;

	bfs();	//用bfs进行dp
	Node k=p[a.size()][b.size()][0];	//根据定义,答案为f[a.size()][b.size()][0],所以从这里开始
	while(k.x>0||k.y>0||k.z>0)
	{
		ans.push_back(k.c);	//将该位置的状态放入答案
		k=p[k.x][k.y][k.z];	//回溯
	}
	ans.push_back(k.c);		//将最后一个位置的状态放入
	reverse(ans.begin(),ans.end());	//因为是倒着放的,因此最后要反过来
	
	for(int i=0;i<ans.size();i++)
	cout<<ans[i];
	
	return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

lwz_159

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

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

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

打赏作者

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

抵扣说明:

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

余额充值