Loading

洛谷P2758编辑距离(线性DP)

题目描述

设A和B是两个字符串。我们要用最少的字符操作次数,将字符串A转换为字符串B。这里所说的字符操作共有三种:

1、删除一个字符;

2、插入一个字符;

3、将一个字符改为另一个字符;

!皆为小写字母!

输入格式

第一行为字符串A;第二行为字符串B;字符串A和B的长度均小于2000。

输出格式

只有一个正整数,为最少字符操作次数。

输入输出样例

输入 #1 
sfdqxbw
gfdgw
输出 #1
4
令dp[i][j]代表的含义为将a串的前i个字符转化为b串的前j个字符所需要的最少操作次数。在写转移方程的时候考虑这么几种情况:
1.a[i-1]==b[j-1](a[i-1]为a的第i个字符:则dp[i][j]=dp[i-1][j-1]相等时无需进行操作。
2.a[i-1]!=b[j-1]:dp[i][j]=min(dp[i-1][j-1]+1,dp[i][j-1]+1,dp[i-1][j]+1) 含义分别为替换,插入和删除。替换比较好理解,直接在dp[i-1][j-1]基础上加上替换的一步操作即可。插入因为是在a[i]插入了一个与b[j]相同的字符,所以这里认为a串第i个之前与b串第j-1个之前的字符经过dp[i][j-1]次操作匹配了,只需要再增加一次添加操作。对a的插入可以看作与对b的删除互为逆运算,类比一下可理解。
可以联想一下stud转换为study,求dp[4][5]。按照人的思维肯定考虑插入,相当于dp[4][4]+1。
#include <bits/stdc++.h>
using namespace std;
char a[3010];
char b[3010];
int dp[3010][3010]={0};//dp[i][j]表示a串的前i个字符转换成b串的前j个字符需要的最少步数 
int mmin(int a,int b,int c)
{
    return min(a,min(b,c));
}
int main()
{
    memset(a,0,sizeof(a));
    memset(b,0,sizeof(b));
    memset(dp,0,sizeof(dp));
    scanf("%s",a);
    scanf("%s",b);
    int i,j;
    dp[0][0]=0;
    for(i=1;i<=strlen(a);i++)
    {
        dp[i][0]=i;//边界 
    } 
    for(j=1;j<=strlen(b);j++)
    {
        dp[0][j]=j;
    } 
    for(i=1;i<=strlen(a);i++)
    {
        for(j=1;j<=strlen(b);j++)
        {
            if(a[i-1]==b[j-1])dp[i][j]=dp[i-1][j-1];//不用转换的情况 注意i,j的含义以及下标是否要-1 
            else dp[i][j]=mmin(
                dp[i-1][j-1]+1,//编辑
                dp[i][j-1]+1,//插入 因为是在a[i]插入了一个与b[j]相同的字符,所以这里认为a串第i个之前与b串第j-1个之前的字符经过dp[i][j-1]次操作 匹配了,只需要再增加一次添加操作即可 
                dp[i-1][j]+1//删除  同理 
            ); 
        }
    }
    cout<<dp[strlen(a)][strlen(b)]<<endl;
    return 0;
}

 

posted @ 2020-02-07 14:46  脂环  阅读(175)  评论(0编辑  收藏  举报