问题描述
对于长度相同的两个字符串A和B,其距离定义为相应位置字符距离之和。两个非空格字符的距离是它们的ASCII编码之差的绝对值。空格与空格的距离为0,空格与其他字符的距离为一定值k。
在一般情况下,字符串A和B和长度不一定相同。字符串A的扩展是在A中插入若干空格字符所产生的字符串。在字符串A和B的所有长度相同的扩展中,有一对距离最小的扩展,该距离称为字符串A和B的扩展距离。
对于给定的字符串A和B,试设计一个算法,计算其扩展距离。
样例输入
cmc
snmn
2
样例输出
10
样例说明
对于A,B两字符串可扩展成以下两种形式,距离为10
c mc
snm n
分析
用数组dp[i][j]
来记录A,B两串扩展后的对应字符a[i]
和b[j]
的距离
对于每一个a[i]
和b[j]
都有以下三种可能
1、a[i]
是字符,b[j]
是空格,则dp[i][j]=dp[i-1][j]+k
2、a[i]
是空格,b[j]
是字符,则dp[i][j]=dp[i][j-1]+k
3、a[i]
是字符,b[j]
是字符,则dp[i][j]=dp[i-1][j-1]+abs(a[i]-b[j])
所以状态转移方程为:dp[i][j]=min{dp[i-1][j]+k,dp[i][j-1]+k,dp[i-1][j-1]+abs(a[i]-b[j])}
注意: 为了防止数组越界,要先判断i和j与1的大小关系
代码
#include <iostream>
#include <cmath>
using namespace std;
const int MAX = 1e3+5; //标识最大的可能整数
const int INF = 0x3f3f3f3f;
int dp[MAX][MAX];
string a; //字符串A
string b; //字符串B
int k; //定值k
int solve()
{
int len1, len2;
int temp;
dp[0][0] = 0;
len1 = a.length();
len2 = b.length();
for (int i = 0; i <= len1; i++) //字符串A和B的有效下标是1~len,下标0表示空字符串
{
//i或j是0表示A或B串为空串
for (int j = 0; j <= len2; j++)
{
if (i + j) //i和j至少一个大于0
{
dp[i][j] = INF;
temp = dp[i - 1][j] + k;
if (i && (temp < dp[i][j])) //i大于0
dp[i][j] = temp;
temp = dp[i][j - 1] + k;
if (j && (temp < dp[i][j])) //j大于0
dp[i][j] = temp;
temp = dp[i - 1][j - 1] + abs(a[i] - b[j]);
if ((i * j) && (temp < dp[i][j])) //i和j至少有一个不为0
dp[i][j] = temp;
}
}
}
return dp[len1][len2];
}
int main()
{
cin >> a >> b >> k;
a = " " + a;
//此处在字符串开头添加一个空格,是为了使字符串a的有效字符下标从1到a.length()
b = " " + b;
cout << solve() << endl;
return 0;
}