Codeforces Round #605 (Div. 3) F. Two Bracket Sequences 三维dp
题目链接:http://codeforces.com/contest/1272/problem/F
题意:给两个括号序列 s1,s2,要求构造一个最短的规范的括号序列 ans,且满足 s1,s2为 ans 的子序列。
设有三维dp[i][j][k],表示s1串取到i,第二个字符串取到j,k=左括号数-右括号数,dp[i][j][k]为最小长度
k相当于一个栈的思想,加入一个s1或s2出现的左括号时,k++,加入一个s1或s2出现过的右括号时,(k非0)匹配掉了一个左括号k--,加入左括号右括号相当于入栈出栈
当dp[i][j][k]:
k想变成k+1时,必须在s1[i+1]或s2[j+1]出现过一个'('
如果出现在s1[i+1],则dp[i+1][j][k+1]=min(dp[i+1][j][k+1],dp[i][j][k]+1)
如果出现在s2[j+1],则dp[i][j+1][k+1]=min(dp[i][j+1][k+1],dp[i][j][k]+1)
如果同时出现,则相当于加入的左括号为s1、s2共有,dp[i+1][j+1][k+1]=min(dp[i+1][j+1][k+1],dp[i][j][k]+1)
需要用个last数组(pre)标记路径
当k想变成k-1(加右括号时)同理
在做pre处理时可以不用开结构体
pre[tmpi][tmpj][tmpk]=i*1e6+j*1e3+k;
也可以开个char s[maxn][maxn][maxn],来记录s[i][j][k]对应的是左括号还是右括号
附上代码:
#include<bits/stdc++.h> using namespace std; #define inf 0x3f3f3f3f const int maxn=200+10; char s1[maxn],s2[maxn]; int dp[maxn][maxn][maxn*2],n,m,tol; struct node { int x,y,z; }pre[maxn][maxn][maxn*2]; int main() { scanf("%s%s",s1+1,s2+1); n=strlen(s1+1); m=strlen(s2+1); tol=0; for(int i=1;i<=n;i++)tol+=s1[i]=='('; for(int i=1;i<=m;i++)tol+=s2[i]=='('; tol=max(tol,n+m-tol);//max(左括号数,右括号数) memset(dp,inf,sizeof dp); dp[0][0][0]=0; /* dp[i][j][k],s1串取到i,第二个字符串取到j,k=左括号数-右括号数,dp[i][j][k]为最小步数 s1的前i位是目前序列的子序列 s2的前j位是目前序列的子序列 答案为dp[n][m][0] */ for(int i=0;i<=n;i++) { for(int j=0;j<=m;j++) { for(int k=0;k<=tol;k++) { //放入一个'(',如果s1[i+1]是左括号,则放入的是s1[i+1]的左括号 //如果s2[j+1]和s1[i+1]都是左括号,则表明新构成的序列里的这个括号既是s1[i+1],又是s2[j+1] int tmpi=i,tmpj=j,tmpk=k+1; if(dp[i][j][k]==inf)continue; if(s1[i+1]=='(')tmpi++; if(s2[j+1]=='(')tmpj++; if(dp[tmpi][tmpj][tmpk]>dp[i][j][k]+1)//当s1[i+1]和s2[j+1]都没有左括号时,此语句不会为true { dp[tmpi][tmpj][tmpk]=dp[i][j][k]+1; pre[tmpi][tmpj][tmpk]={i,j,k}; } if(!k)continue;//保证k足够 tmpi=i,tmpj=j,tmpk=k-1; //放入一个')',因为k为左括号数-又括号数,所以加入右括号后匹配上了一个左括号,k+1-2=k-1 if(s1[i+1]==')')tmpi++; if(s2[j+1]==')')tmpj++; if(dp[tmpi][tmpj][tmpk]>dp[i][j][k]+1) { dp[tmpi][tmpj][tmpk]=dp[i][j][k]+1; pre[tmpi][tmpj][tmpk]={i,j,k}; } } } } int id=0; for(int i=1;i<=tol;i++) { if(dp[n][m][i]+i<dp[n][m][id]+id)id=i;//从dp[n][m][0]到dp[n][m][i]要加i个左括号,即为i步 } vector<char> vec; node now={n,m,id}; while(now.x||now.y||now.z)//最后一步变成000 { vec.push_back(now.z>pre[now.x][now.y][now.z].z?'(':')');//用z来判断,如果是右括号,z是会变小的 now=pre[now.x][now.y][now.z]; } int size=vec.size(); for(int i=size-1;i>=0;i--)printf("%c",vec[i]); for(int i=1;i<=id;i++)printf(")"); return 0; }