一种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;
}