最短编辑距离


这两天玩疯了....之前学过了忘了不少,又捡起来重新复习...

废话不说了,上题

给定两个字符串 A">AA 和 B">BB,现在要将 A">AA 经过若干操作变为 B">BB,可进行的操作有:

  1. 删除–将字符串 A">AA 中的某个字符删除。
  2. 插入–在字符串 A">AA 的某个位置插入某个字符。
  3. 替换–将字符串 A">AA 中的某个字符替换为另一个字符。

现在请你求出,将 A">AA 变为 B">BB 至少需要进行多少次操作。

输入格式

第一行包含整数 n">nn,表示字符串 A">AA 的长度。

第二行包含一个长度为 n">nn 的字符串 A">AA。

第三行包含整数 m">mm,表示字符串 B">BB 的长度。

第四行包含一个长度为 m">mm 的字符串 B">BB。

字符串中均只包含大写字母。

输出格式

输出一个整数,表示最少操作次数。

数据范围

1n,m1000">1n,m10001≤n,m≤1000

输入样例:

10 
AGTCTGACGC
11 
AGTAAGTAGGC

输出样例:

4
令f[i][j]为a序列1~i变为b序列1~j的最小的操作次数
这个为状态转移式
然后一共有三类操作
a序列的删,增,改
删:代表了a序列1~i再删一个就可以与b序列匹配,(意味着a序列此时必b序列多一个(不要管后面的先))
这么想吧,假定删除这部操作已经结束了,那i-1与j已经匹配了,那这个的最小操作次数就是f[i-1][j]啊,再加上这步删除的操作,就是f[i-1][j]+1
增:代表了j比i多了1,此时的序列a的1~i与b的1~j-1相匹配,最后加上现在的这个增的操作:f[i][j]=f[i][j-1]+1;
改:此时的a序列1~i-1与b序列的1~j-1已经匹配,再改一下现在的操作:f[i-1][j-1]+1(但这个是需要在a[i]!=b[j]的情况下,需要特判)
(增和改同理删)
#include
using namespace std;
const int N=1010;
char a[N],b[N];
int n,m;
int f[N][N];
int main(){
    cin>>n>>a+1;
    cin>>m>>b+1;
    for(int i=0;i<=m;i++) f[0][i]=i;//初始化a从0开始到b只可能增加,次数就是i
    for(int i=0;i<=n;i++) f[i][0]=i;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            f[i][j]=min(f[i-1][j]+1,f[i][j-1]+1);
            if(a[i]==b[j])
                f[i][j]=f[i-1][j-1];//一样的就是与f[i-1][j-1]的最小值等价 
            else
                f[i][j]=min(f[i][j],f[i-1][j-1]+1);
        }
    } 
    cout<endl;
    return 0;
}
/*
f[i][j]表示a的前1个字母变到b的前j个字母的最小操作次数 

*/

 *******************************************************

哈哈,我又来了,下一节的编辑距离就是和这个差不多吧,就放一起写了

给定 n">nn 个长度不超过 10">1010 的字符串以及 m">mm 次询问,每次询问给出一个字符串和一个操作次数上限。

对于每次询问,请你求出给定的 n">nn 个字符串中有多少个字符串可以在上限操作次数内经过操作变成询问给出的字符串。

每个对字符串进行的单个字符的插入、删除或替换算作一次操作。

输入格式

第一行包含两个整数 n">nn 和 m">mm。

接下来 n">nn 行,每行包含一个字符串,表示给定的字符串。

再接下来 m">mm 行,每行包含一个字符串和一个整数,表示一次询问。

字符串中只包含小写字母,且长度均不超过 10">1010。

输出格式

输出共 m">mm 行,每行输出一个整数作为结果,表示一次询问中满足条件的字符串个数。

数据范围

1n,m1000">1n,m10001≤n,m≤1000,

输入样例:

3 2
abc
acd
bcd
ab 1
acbd 2

输出样例:

1
3
#include
#include
using namespace std;
const int N=15,M=1010;
int f[N][N];
char str[M][N];//
int n,m;
int dis(char a[],char b[])
{
    int la,lb;
    la=strlen(a+1);
    lb=strlen(b+1);
    for(int i=0;i<=lb;i++) f[0][i]=i;
    for(int i=0;i<=la;i++) f[i][0]=i;
    for(int i=1;i<=la;i++)
    {
        for(int j=1;j<=lb;j++)
        {
            f[i][j]=min(f[i-1][j]+1,f[i][j-1]+1);
            if(a[i]==b[j])
                f[i][j]=f[i-1][j-1];
            else
                f[i][j]=min(f[i][j],f[i-1][j-1]+1);
        }
    }
    return f[la][lb];
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>str[i]+1;
    while(m--)
    {
        char ch[15];
        int x;
        cin>>ch+1>>x;
        int t=0;
        for(int i=1;i<=n;i++)
        {
            if(dis(str[i],ch)<=x)
                t++;
        }
        cout<endl;
    }
    return 0;
}
记住所有都要下标从1开始,不然可能数组越界(要是你喜欢特判来折腾当我没说)