【jzoj5102】【GDOI2017 day2】【小学生语文题】【动态规划】

题目大意

给出两个串,每次操作可以将当前串的一个字符移到它前面的任意位置,求到目标串的最小操作数及其步骤。

解题思路

对两个串做变种的lcs,f[i][j]表示原串匹配到i,当前串匹配到j的lcs,转移保证i不小于j且前i个字符包含前j个字符。用另外的数组保留转移方式,构造解的时候贪心构造即可。

code

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LF double
#define LL long long
#define ULL unsigned long long
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define fr(i,j,k) for(int i=begin[j][k];i;i=next[j][i])
using namespace std;
int const mn=2000+9,inf=1e9+7;
int t,n,cnt1[30],cnt2[30],match[mn],tag[mn],f[mn][mn],pi[mn][mn],pj[mn][mn];
char s1[mn],s2[mn];
int main(){
    //freopen("chinese.in","r",stdin);
    //freopen("chinese.out","w",stdout);
    freopen("d.in","r",stdin);
    freopen("d.out","w",stdout);
    scanf("%d\n",&t);
    fo(cas,1,t){
        scanf("%s\n%s\n",s1+1,s2+1);int n=strlen(s1+1);
        fo(i,1,n)fo(j,1,n)f[i][j]=0;
        fo(i,0,25)cnt1[i]=cnt2[i]=0;
        int k=1;cnt1[s1[1]-'a']=1;
        fo(j,1,n){
            int ch=s2[j]-'a';cnt2[ch]++;
            for(;cnt1[ch]<cnt2[ch];k++){
                cnt1[s1[k+1]-'a']++;
                if(f[k-1][j]>f[k][j]){
                    f[k][j]=f[k-1][j];
                    pi[k][j]=k-1;pj[k][j]=j;
                }
            }
            fo(i,k,n){
                int tmp=max(f[i-1][j],f[i][j-1]),tmpp=max(tmp,f[i-1][j-1]+(s1[i]==s2[j]));
                f[i][j]=tmpp;
                if(tmpp==f[i-1][j])pi[i][j]=i-1,pj[i][j]=j;
                else if(tmpp==f[i][j-1])pi[i][j]=i,pj[i][j]=j-1;
                else pi[i][j]=i-1,pj[i][j]=j-1;
            }
        }
        int i=n,j=n;
        fo(i,1,n)match[i]=tag[i]=0;
        while(i&&j){
            while((pi[i][j]==i)||(pj[i][j]==j)){
                int ni=pi[i][j],nj=pj[i][j];
                i=ni;j=nj;
            }
            match[i]=j;tag[j]=1;
            int ni=pi[i][j],nj=pj[i][j];
            i=ni;j=nj;
        }
        printf("%d\n",n-f[n][n]);
        fo(i,1,n)if(!match[i]){
            int tmp;
            fo(j,i+1,n)if((!tag[j])&&(s1[i]==s2[j])){tmp=j;break;}
            printf("%d %d\n",tmp,i);
            fo(j,i+1,n)if(match[j]&&(match[j]<=tmp)){
                tag[match[j]]--;
                tag[++match[j]]++;
            }
            int tmpp=s2[tmp];
            fd(j,tmp,i+1)s2[j]=s2[j-1];
            s2[i]=tmpp;
        }
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值