CF 1272F Two Bracket Sequences (括号dp)

题目地址

洛谷CF1272F

Solution

首先题目中有两个括号串 \(s\)\(t\) ,考虑先设计两维表示 \(s\) 匹配到的位置和 \(t\) 匹配到的位置。

接着根据 括号dp的一般套路:设计一维表示当前栈中的左括号数量 (ygt大佬喜欢形象地把其称为 “前缀和”),所以状态就出来了:

\[f[i,j,k] \texttt{表示 s 匹配到 i , t 匹配到 j , 栈中有 k 个左括号,的最小新序列长度} \]

转移挺简单的,新序列要么增加一个 '(' , 要么增加一个 ')' , 直接转移即可。

但是转移的阶段顺序很难写,但是 根据递推不好写我们就递归的原则 我们可以写一个 记忆化搜索。具体实现和路径输出请看代码。

Code

Talk is cheap.Show me the code.

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
inline int read() {
	int x=0,f=1; char ch=getchar();
	while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
	while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); }
	return x * f;
}
const int N = 207;
int n,m;
int dp[N][N][N<<1];
char s[N],t[N],op[N][N][N<<1];
struct Node {
	int x,y,z;
}pr[N][N][N<<1];
int Solve(int i,int j,int k) {
	if(dp[i][j][k] != -1) return dp[i][j][k];
	if(i==n+1 && j==m+1) return k;            //栈中还有k个左括号,我们要k个右括号与之匹配
	int res1 = INF, res2 = INF, ni1 = ((i<=n&&s[i]=='(')?i+1:i), nj1 = ((j<=m&&t[j]=='(')?j+1:j), ni2 = ((i<=n&&s[i]==')')?i+1:i), nj2 = ((j<=m&&t[j]==')')?j+1:j);
	if(k <= 200) res1 = Solve(ni1,nj1,k+1) + 1;
	if(k > 0) res2 = Solve(ni2,nj2,k-1) + 1;
	if(res1 < res2) {
		op[i][j][k] = '('; dp[i][j][k] = res1; pr[i][j][k] = (Node)<%ni1,nj1,k+1%>;
	} else {
		op[i][j][k] = ')'; dp[i][j][k] = res2; pr[i][j][k] = (Node)<%ni2,nj2,k-1%>;
	}
	return dp[i][j][k];
}
void Print(int i,int j,int k) {
	Node tmp = pr[i][j][k];
	if(op[i][j][k]=='(' || op[i][j][k]==')') cout<<op[i][j][k];
	if(tmp.x!=-1) Print(tmp.x, tmp.y, tmp.z);
	else {
		for(int l=1;l<=k;++l) cout<<')';    //输出这k个右括号
	}
}
int main()
{
	//freopen("My.out","w",stdout);
	scanf("%s%s",s+1,t+1);
	n = strlen(s+1), m = strlen(t+1);
	memset(dp, -1, sizeof(dp));
	memset(pr, -1, sizeof(pr));
	Solve(1,1,0);
	Print(1,1,0);
	return 0;
}

Summary

重点在了解括号dp的一般套路。

posted @ 2019-12-16 21:30  基地AI  阅读(435)  评论(0编辑  收藏  举报