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的一般套路。

猜你喜欢

转载自www.cnblogs.com/BaseAI/p/12051489.html