#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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#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;
}

你可能感兴趣的:(Codeforces)