SPOJ 6219 Edit distance字符串间编辑距离

题目地址http://www.spoj.com/problems/EDIST/

题目描述:给定字符串s1,字符串s2(长度<=2000)

求将s1转换为s2最小操作数:1、添加一个字符;2、删除一个字符;3、变更一个字符

分析最优子结构

dp[i][j]为s1串到第i个位置,s2到第j个位置时的最小布数,

则dp (i,j)=   dp(i-1,j-1),s1(i)==s2(j)

                         min(dp(i-1,j)+1,dp(i,j-1)+1 ) ,s1(i)!=s2(j)

还是来分析前一个状态的最优子结构:

例如:s1=“asdfas”

         s2=“axefsa”

如果s1(i)=s2(j),不用做任何操作。即使前面出现了“asda”,“fewaa”这种情况dp(4,5)=dp(3,4)都能保证依旧最优解因为s2最多有1个‘a’与s1的‘a’配对,

                                 反过来想,前面dp(i-1,j-1)已经保证了最优子结构,且前面的dp(i-1,j-1)对后面的s1(i),s2(j)无影响。

      s1(i)!=s2(j),则有3种选择:

dp(i)(j)=

1、s1(i)变成s2(j),dp(i-1)(j-1)+1;

2、在s1中删除s1(i),dp(i-1)(j)+1,暗含一个条件,即删除s1(i)后s1‘与s2'是相同的那么说明在dp(i-1)(j)中形成的两个串和删除s1(i)的两个串是一样的,所以和现在s1(i)无关,所以前一个最优状态是dp(i-1)(j)

3、在s1中第i个位置上添加一个s2(j),dp(i)(j-1)+1,那说明什么呢?当我们要判断s2(j)时发现s1‘上少了一个和s2(j)相同的字母。

想一想,已经没有其他可供修改的操作了,所以是在这枚举这3种后取一个最小值。

递推代码:

#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
int c[2005][2005];
char s1[2005],s2[2005];
int mins(int a,int b,int c){
    if (a<=b && a<=c) return a;
    else if (b<=c) return b;else return c;
}
int dp(int l,int r){
    c[0][0]=0;//边界处理
    for(int i=1;i<=l;i++)c[i][0]=i;//表示s1要删除的个数为i
    for(int j=1;j<=r;j++)c[0][j]=j;//s1要添加的个数为j
    for(int i=1;i<=l;i++){
        for(int j=1;j<=r;j++)
        if(s1[i-1]==s2[j-1]) c[i][j]=c[i-1][j-1];//递推
        else c[i][j]=mins(c[i-1][j-1]+1,c[i][j-1]+1,c[i-1][j]+1);
    }
    return c[l][r];
}
int main(){
//    freopen("in","rb",stdin);
//    freopen("out","wb",stdout);
    int t;
    scanf("%d",&t);
    while(~scanf("%s%s",s1,s2)){
        int l=strlen(s1),r=strlen(s2);
        printf("%d
",dp(l,r));

    }
    return 0;
}

  递归代码:

#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
int c[2005][2005];
int vis[2005][2005];
char s1[2005],s2[2005];
int mins(int a,int b,int c){
    if (a<=b && a<=c) return a;
    else if (b<=c) return b;else return c;
}
int dp(int l,int r){
    int &ans=c[l][r];
    if (vis[l][r]) return ans;
    vis[l][r]=1;
    if (l==0) return ans=r;
    if (r==0) return ans=l;
    if (s1[l-1]==s2[r-1]) ans=dp(l-1,r-1);
    else ans=mins(dp(l,r-1)+1,dp(l-1,r)+1,dp(l-1,r-1)+1);
    return ans;
}
int main(){
//    freopen("in","rb",stdin);
//    freopen("out","wb",stdout);
    int t;
    scanf("%d",&t);
    while(~scanf("%s%s",s1,s2)){
        int l=strlen(s1),r=strlen(s2);
        memset(vis,0,sizeof(vis));
        printf("%d
",dp(l,r));

    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/little-w/p/3449389.html