P2453 [SDOI2006]最短距离-动态规划

版权声明:原创,勿转 https://blog.csdn.net/qq_42386465/article/details/82854199

一种EDIT字母编辑器,它的功能是可以通过不同的变换操作可以把一个源串X [l..m]变换为新的目标串y[1..n]。EDIT提供的变换操作有:

源串中的单个字符可被删除(delete);

被替换 (replace);

被复制到目标串中去(copy);

字符也可被插入(insert);

源串中的两个相邻字符可进行交换并复制到目标串中去(twiddle);

在完成其它所有操作之后,源串中余下的全部后缀就可用删至行末的操作删除(kill)。

例如,将源"algorithm"转换成目标串"altruistic"的一种方法是采取下面的操作序列:

要达到这个结果还可能有其它一些操作序列。

操作delete,replace,copy,insert,twiddle和kill中每一个都有一个相联系的代价cost。例如

cost(delete)=3;
cost(replace)=6;
cost(copy)=5;
cost(insert)=4;
cost(twiddle)=4;
cost(kill)=被删除的串长*cost(delete)-1;

一个给定的操作序列的代价为序列中各操作代价之和。 例如上述操作序列的代价为

3*cost(copy)+2*cost(replace)+cost(delete)+3*cost(insert) + cost(twiddle) +cost(kill)

=3*5+2*6+3+3*4+4+1*3-1=48

编程任务:

给定两个序列x[1..m],y[1..n]和一些操作代价集合,X到Y的最短距离为将X转化为Y的最小的转换序列的代价。请给出一个算法来找出x[1..m]至y[1..n]的最短距离。

https://www.luogu.org/problemnew/show/P2453

状态:f[i][j]表示初始串初始串删除到第i个字符,目标串完成到第j个字符;

初始串为s1,len1;

目标串为s2,len2;

边界

c[i][0]=cost(delet)*i;(目标串没有字符,初始串只能全删了)

c[0][j]=cost(insert)*j;(初始串一个字符都没有,目标串只能用insert一个一个插进去)

枚举i,枚举j

Copy:当a[i]==b[j]时(此条件需要判断),一样的话就copy就好;

c[i][j]=min(c[i][j],c[i-1][j-1]+cost[copy]);

Repalce:当a[i]!=b[j]时(此条件无需判断),就把初始串的删了,目标串填一个;

c[i][j]=min(c[i][j],c[i-1][j-1]+cost[replace]);

Delet:是删除一个初始串的,对于目标串无影响;

c[i][j]=min(c[i][j],c[i-1][j]+cost[delet]);

Insert:给目标串多完成一个,对初始串无影响;

c[i][j]=min(c[i][j],c[i][j-1]+cost[insert]);

Twiddle:当a[i-1]==b[j]&&a[i]==b[i-1]&&i>=2&&j>=2时(此条件需要判断),就twiddle;

c[i][j]=min(c[i][j],c[i-2][j-2]+cost[twiddle]);

枚举结束!


Kill:单独拿出来,枚举当目标串已经完成的情况下(i=len2),初始串要清零的最小值

c[len1][len2]=min(c[len1][len2],c[i][len2]+cost[delet]*(len1-i)-1);

结果:f[len1][len2]。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<stack>
#define inf 1e18+5
#define ll long long
using namespace std;
ll inline read()
{
    ll 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*10+ch-'0';ch=getchar();}
    return x*f;
}
char a[2050],b[2050];
ll c[2050][2050];
ll cost[6];
int main()
{
    scanf("%s%s",a+1,b+1);
    for(int i=1;i<=5;i++){
        cost[i]=read();
    }
    //1=delet,2=replace,3=copy,4=insert,5=twiddle
    int len1=strlen(a+1),len2=strlen(b+1);
    if(len1==0&&len2==0){
        printf("0");
        return 0;
    }
    if(len1==0&&len2!=0){
        printf("%lld",len2*cost[4]);
        return 0;
    }
    if(len1!=0&&len2==0){
        printf("%lld",len1*cost[1]);
        return 0;
    }
    for(int i=1;i<=len1;i++){
        for(int j=1;j<=len2;j++){
            c[i][j]=inf;
        }
    }
    c[0][0]=0;
    for(int i=1;i<=len1;i++){
        c[i][0]=i*cost[1];
    }
    for(int i=1;i<=len2;i++){
        c[0][i]=i*cost[4];
    }
    for(int i=1;i<=len1;i++){
        for(int j=1;j<=len2;j++){
            if(a[i]==b[j]){
                c[i][j]=min(c[i][j],c[i-1][j-1]+cost[3]);
            }
            c[i][j]=min(c[i][j],c[i-1][j-1]+cost[2]);
            c[i][j]=min(c[i][j],c[i-1][j]+cost[1]);
            c[i][j]=min(c[i][j],c[i][j-1]+cost[4]);
            if(i>=2&&j>=2&&a[i-1]==b[j]&&a[i]==b[j-1]){
                c[i][j]=min(c[i][j],c[i-2][j-2]+cost[5]);
            }
        }
    }
    for(int i=1;i<len1;i++){
        c[len1][len2]=min(c[len1][len2],c[i][len2]+cost[1]*(len1-i)-1);
    }
    printf("%lld",c[len1][len2]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42386465/article/details/82854199
今日推荐