cf1272F——经典升维dp,好题!

/*
给两个括号序列,用一个合法的括号串来覆盖这两个串,求出这个最短串
这个问题可以分解成两个条件:
    1.用一个最短的括号序列来覆盖这两个串 
    2.这个序列要合法
首先考虑第一个条件:
    不难想到用两个状态dp[i,j]来表示匹配s[1..i],t[1..j]时的最短长度
     转移也很简单:初始状态dp[0,0]=0,后面加'(',后面加')':都分别取更新对应状态  
    最后的结果是dp[lens,lent] 

然后再来考虑上第二个条件
    括号序列合法的条件是所有的前缀和>=0,且最后的和是0(懂我意思吧)
    要让最后的串满足这个条件,我们必须在转移时考虑到前缀和状态,这个状态>=0,
    自然想到升一维dp,dp[i,j,k]来表示匹配到s[1..i],t[1..j]且前缀和是k的最短长度
    初始状态dp[0,0,0]=0,转移同上 
    这个前缀和的范围必定在[0,lens+lent],所以整个dp的复杂度是O(n^3) 
最后的答案:
    dp[i,j,k]+k里找个最小的记为mink 
由于要输出解法,所以我们记下前驱即可(这都是细枝末节的实现了) 
*/
#include<bits/stdc++.h>
using namespace std;
#define N 1005

char s[N],t[N];
int dp[205][205][405],lens,lent; 
struct Node{
    int i,j,k,flag,len;
    Node(){}
    Node(int i,int j,int k,int flag,int len):i(i),j(j),k(k),flag(flag),len(len){}
}pre[205][205][405];

stack<char>stk;
void print(Node node){
    if(node.flag==-1)stk.push(')');
    else if(node.flag==1)stk.push('(');
    if(node.len)
        print(pre[node.i][node.j][node.k]);
}

int main(){
    scanf("%s%s",s+1,t+1);
    lens=strlen(s+1);lent=strlen(t+1);
    
    memset(dp,0x3f,sizeof dp);
    dp[0][0][0]=0;
    
    for(int i=0;i<=lens;i++)
        for(int j=0;j<=lent;j++)
            for(int k=0;k<=lens+lent;k++){
                if(dp[i][j][k]==0x3f3f3f3f)continue;
                if(k){//加个右括号 
                    int f1,f2;
                    if(s[i+1]==')')f1=1;
                    else f1=0;
                    if(t[j+1]==')')f2=1;
                    else f2=0;
                    if(dp[i][j][k]+1<dp[i+f1][j+f2][k-1]){//更新状态 
                        Node node=Node(i,j,k,-1,dp[i][j][k]);
                        pre[i+f1][j+f2][k-1]=node;
                        dp[i+f1][j+f2][k-1]=dp[i][j][k]+1;                 
                    } 
                }
                //加个左括号
                int f1,f2;
                if(s[i+1]=='(')f1=1;
                else f1=0;
                if(t[j+1]=='(')f2=1;
                else f2=0;
                if(dp[i][j][k]+1<dp[i+f1][j+f2][k+1]){//更新状态 
                    Node node=Node(i,j,k,1,dp[i][j][k]);
                    pre[i+f1][j+f2][k+1]=node;
                    dp[i+f1][j+f2][k+1]=dp[i][j][k]+1;                 
                } 
            }
    
    int Min=0x3f3f3f3f,mink=0;
    for(int k=1;k<=lens+lent;k++){
        if(dp[lens][lent][k]+k<dp[lens][lent][mink]+mink){
            mink=k;
        }
    } 
    
    for(int i=1;i<=mink;i++)stk.push(')');    
    print(pre[lens][lent][mink]);
    while(stk.size()){
        cout<<stk.top();
        stk.pop();
    }
    puts("");
}

猜你喜欢

转载自www.cnblogs.com/zsben991126/p/12113735.html