题目描述:对于长度相同的2个字符串A和B,其距离定义为所有相应位置字符距离之和。2个非空格字符的距离是它们的ASCII码之差的绝对值;空格与空格的距离为0,空格与其他字符的距离为一个定值k。在一般情况下,字符串A和B的长度不一定相同。字符串A的扩展是在A中插入若干空格字符所产生的字符串。在字符串A和B的所有长度相同的扩展中,有一对距离最短的扩展,该距离称为字符串A和B的扩展距离。对于给定的字符串A和B测试数据:
输入:cmc
snmn
2 (分别表示字符串A、B和定值k)
输出:10,设计一个算法,计算其扩展距离。
样例解释:
用
∗
*
∗代表空格的话
a:
c
∗
∗
m
c
∗
c**m c*
c∗∗mc∗
b:
∗
s
n
m
∗
n
*snm*n
∗snm∗n 这样的话 扩展距离 = 2+2+2+0+2 = 10
算法分析:
这个题我们可以类比于之前的最长公共子序列问题,题目也比较简单,通过动态规划求解,我们定义一个二维数组dp[i][j] 表示第一个字符串已经匹配到第i位,第二个字符串已经匹配到第j位时两者扩展距离的最小值,我们可以看到此时,dp[i][j] 可能由三种情况得到,一种是i和j匹配时扩展距离加上两者的字符的距离dist,另一种是j和(0i-1)中的某一位匹配,剩下i和空格匹配(或者是i和0j-1中某一位匹配,j和空格匹配)此时扩展距离只要加上k就可以了
那么我们很容易得到其中的状态转移方程
d
p
[
i
]
[
j
]
=
m
i
n
(
d
p
[
i
−
1
]
[
j
−
1
]
+
d
i
s
t
(
i
,
j
)
,
m
i
n
(
d
p
[
i
−
1
]
[
j
]
+
t
,
d
p
[
i
]
[
j
−
1
]
+
t
)
)
dp[i][j]=min(dp[i-1][j-1]+dist(i,j),min(dp[i-1][j]+t,dp[i][j-1]+t))
dp[i][j]=min(dp[i−1][j−1]+dist(i,j),min(dp[i−1][j]+t,dp[i][j−1]+t))
最后考虑一下边界条件,如果i或者j=0的话, dp[i][0]=ik , dp[0][j]=jk;因为都和空格进行了匹配
代码如下
#include <bits/stdc++.h>
using namespace std;
const int maxn=5000;
int dp[maxn][maxn];
string s,k;
int dist(int i,int j)
{
int p1=s[i-1]-'a';
int p2=k[j-1]-'a';
return abs(p1-p2);
}
int main()
{
memset(dp,0,sizeof(dp));
cin>>s>>k;
int t;
cin>>t;
int len = max(s.size(),k.size());
memset(dp,0,sizeof(dp));
for(int i=1;i<=s.size();i++)
{
dp[i][0]=t*i;
}
for(int i=1;i<=k.size();i++)
{
dp[0][i]=t*i;
}
for(int i=1;i<=s.size();i++)
{
for(int j=1;j<=k.size();j++)
{
dp[i][j]=min(dp[i-1][j-1]+dist(i,j),min(dp[i-1][j]+t,dp[i][j-1]+t));
}
}
int len1=s.size();
int len2=k.size();
cout<<dp[len1][len2]<<endl;
return 0;
}