cf1272F——经典升维dp,好题!
Posted zsben991126
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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(""); }
以上是关于cf1272F——经典升维dp,好题!的主要内容,如果未能解决你的问题,请参考以下文章