给你两个字符串,a和b,通过四种操作:
在任意位置添加一个字符花费为t1
删除任意一个字符花费为t2
改变任意一个字符花费为t3
交换相邻字符花费为t4
使字符串a用最小花费变为b。
如果没有第四种操作这题就成水dp了。所以先看前三种操作。
令f[i][j]表示匹配字符串a的前i项与字符串b的前j项的最小花费,则有
f[i][j]=min( f[i-1][j]+t2, f[i][j-1]+t1 );
if (a[i]==b[j]) f[i][j]=min( f[i][j], f[i-1][j-1] );
else f[i][j]=min( f[i][j], f[i-1][j-1]+t3 );
f[i][0]=t2*i;f[0][i]=t1*i;
再考虑第四种操作。
若匹配字符串XXXbXXXa和XXaXXb,当i=8,j=6时,若想使字符串1的'a'字符与字符串2的'b'字符通过交换完成匹配,则必须从串1中找到字符'b'从串2中找到字符'a',若有一个无法找到,则该状态不能通过交换得到。考虑pi=4,pj=3之前已匹配好的情况,若想交换'a'和'b'则'a''b'必须相邻,则删除串1中'b''a'之间的所有元素,花费(i-pi-1)*t2,此时'a''b'相邻,交换ab,花费为t4,添加串2中'a''b'之间的所有元素,花费(j-pj-1)*t1,此时i,j的状态由交换完成匹配。由题意知2· te ≥ ti + td表示两次字符交换的花费大于添加与删除之和。
---------------------------------------------------------------------------------------------------------------------------
#include <iostream>
#include <cstring>
using namespace std;
char a[4444],b[4444];
int lena,lenb;
int f[4444][4444];
int ca[4444][256];
int cb[4444][256];
int t1,t2,t3,t4;
int pa,pb;
int main()
{
while (cin>>t1>>t2>>t3>>t4)
{
memset(f,0,sizeof(f));
memset(ca,0,sizeof(ca));
memset(cb,0,sizeof(cb));
cin>>(a+1)>>(b+1);
lena=strlen(a+1);
lenb=strlen(b+1);
for (int i=1;i<=lena;i++)
{
f[i][0]=t2*i;
for (int j='a';j<='z';j++)
{
ca[i][j]=ca[i-1][j];
}
ca[i][a[i]]=i;
}
for (int i=1;i<=lenb;i++)
{
f[0][i]=t1*i;
for (int j='a';j<='z';j++)
{
cb[i][j]=cb[i-1][j];
}
cb[i][b[i]]=i;
}
for (int i=1;i<=lena;i++)
{
for (int j=1;j<=lenb;j++)
{
f[i][j]=min( f[i-1][j]+t2, f[i][j-1]+t1 );
if (a[i]==b[j]) f[i][j]=min( f[i][j], f[i-1][j-1] );
else f[i][j]=min( f[i][j], f[i-1][j-1]+t3 );
pa=ca[i-1][b[j]];
pb=cb[j-1][a[i]];
if (pa!=0&&pb!=0)
{
f[i][j]=min( f[i][j], f[pa-1][pb-1]+t4+(i-pa-1)*t2+(j-pb-1)*t1 );
}
}
}
cout<<f[lena][lenb]<<endl;
}
return 0;
}