动态规划——最小编辑代价

1.问题描述

上一次说了最小编辑距离,这次在这上面加一点料,a1、a2和a3每次操作的代价不同了,加入了每个操作的代价,这下问题变为,针对字符串a和字符串b定义三种操作,a1、a2、a3:
a1:修改a中一个字符,代价为A
a2:插入一个字符到a中,代价为B
a3:从a中删除一个字符,代价为C
经过这三种操作,将a变换成b,在给定a和b的情况下,求需要的最小代价

2.问题分析

该问题同样是一个动态规划求解问题,首先构建动态规划矩阵进行分析。假设a字符串“abcd”,b字符串“acde”,以a字符串为列,b字符串为行,构建动态规划矩阵如下所示。

a c d e
a
b
c
d

现在的问题是要将列逐渐变成行,即将字符串a变成b,关键问题是填充上述矩阵元素值的方法。我们可以看到,矩阵的第一行,和第一列可以直接比较得出,即第一行字符“a”变成字符串b需要的操作,“a”变成第一列“a”,。两字符相等,不需要操作;“a”变成字符串“ab”需要再右侧基础上加一部插入操作,所以在矩阵[0,0]位置加上一部插入,变成矩阵[0,1]位置;依次类推,我们可以逐渐插入字符,从字符串“a”变成b,得到矩阵第一行的操作次数记录,这时记得插入操作的代价为B。同理,按列操作,可以得到a变换成字符“a”的操作次数,这里是删除操作,代价为C。如此得到矩阵第一行和第一列,如下所示。

a c d e
a 0 B 2B 3B
b C
c 2C
d 3C

下面是计算的关键部分,就是如何计算矩阵中如下元素的值,可以看到,在矩阵中,从上方[i-1,j]到[i,j]为删除操作,代价为C,从左侧[i,j-1]到[i,j]为插入操作,代价为B,从左上方[i-1,j-1]到[i,j]是修改操作,如果此时a[i]!=b[j],执行修改,代价为A。

a c d e
a 0 B 2B 3B
b C min(n1,n2,n3)
c 2C
d 3C |

从矩阵可以得出规律,每次需要操作时,都在$$[i-1,j-1]$$(i表示行,j表示列),$$[i-1,j]$$和$$[i,j-1]$$三个位置的基础上,计算当前元素[i,j]是否需要进行操作。根据[i-1,j],[i,j-1]和[i-1,j-1]三个位置的取值最小的值来判断进行的操作,加上操作的代价Cost,即为当前[i,j]的取值。最终结果取这三个值的最小值。可以得到动态规划方程:

int ncostA = 0, ncostB = nB, ncostC = nC;
if (a[i] != b[j])
{
    ncostA = A;
}
[i,j] = min([i-1,j] + ncostC, [i,j-1] + ncostB, [i-1,j-1] + ncostA);

通过规划方程,对矩阵所有元素进行赋值,最终矩阵右下角次数值即为所求最少操作次数。为了编程方便,我们在构建矩阵时在原有字符串前加入一个标识位,假设A=1,B=2,C=3,得到如下矩阵。

a c d e
0 2 4 6 8
a 3 0 2 4 6
b 6 3 1 3 5
c 9 6 3 2 4
d 12 9 6 3 3

3代码

int min(int a, int b)
{
    if (a < b)
    {
        return a;
    }
    else
    {
        return b;
    }
}

int min(int a, int b, int c)
{
    int ntemp1 = min(a, b);
    int ntemp2 = min(b, c);

    if (ntemp1 < ntemp2)
    {
        return ntemp1;
    }
    else
    {
        return ntemp2;
    }
}

int minEditNumber(char *src, char * dst, int nA, int nB, int nC)
{
    int nsrc = strlen(src);
    int ndst = strlen(dst);

    if (0 == nsrc)
    {
        return ndst;
    }
    else if (0 == ndst)
    {
        return nsrc;
    }

    int **pnmatrix = new int* [nsrc + 1];

    for (int n = 0; n <= nsrc; n++)
    {
        pnmatrix[n] = new int[ndst + 1];
    }

    for (int i = 0; i <= nsrc; i++)
    {
        pnmatrix[i][0] = i*nC;
    }

    for (int j = 0; j <= ndst; j++)
    {
        pnmatrix[0][j] = j*nB;
    }

    for (int i = 1; i <= nsrc; i++)
    {
        for (int j = 1; j <= ndst; j++)
        {
            int ncost = 0;
            if (src[i-1] != dst[j-1])
            {
                ncost = nA;
            }
            pnmatrix[i][j] = min(pnmatrix[i - 1][j - 1] + ncost, pnmatrix[i - 1][j] + nC, pnmatrix[i][j - 1] + nB);
        }
    }

    //print matrix
    for (int i = 0; i <= nsrc; i++)
    {
        for (int j = 0; j <= ndst; j++)
        {
            cout << pnmatrix[i][j] << " ";
        }
        cout << endl;
    }

    int nReturn = pnmatrix[nsrc][ndst];

    for (int i = 0; i <= nsrc; i++)
    {
        delete[] pnmatrix[i];
        pnmatrix[i] = NULL;
    }
    delete[] pnmatrix;
    pnmatrix = NULL;

    return nReturn;
}

int main()
{
    char *p1 = "abcd";
    char *p2 = "acde";

    int nNo = minEditNumber(p1, p2,1,2,3);
}

原创文章,作者:admin,如若转载,请注明出处:https://www.isclab.org.cn/2015/11/09/%e5%8a%a8%e6%80%81%e8%a7%84%e5%88%92-%e6%9c%80%e5%b0%8f%e7%bc%96%e8%be%91%e4%bb%a3%e4%bb%b7/

(1)
adminadmin
上一篇 2015年9月9日
下一篇 2016年1月21日

相关推荐

  • 机器合成数据生成与评价方法

    本学术报告系统梳理了机器合成数据生成技术(GAN/VAE/扩散模型)的发展脉络,重点解读了两篇顶会论文——TabDiff(ICLR 2025,面向表格数据的混合型扩散模型)和Fai…

    2026年6月8日
    1.0K
  • 二进制代码反编译技术

    二进制代码反编译技术在漏洞检测、恶意代码分析等逆向工程领域中具有重要应用,显著提升了全检安全分析的效率与深度。该技术有助于高效理解和重构二进制程序,支持其修复、维护与再开发。本次报…

    2025年4月9日
    3.6K
  • 多视图聚类技术

    多视图聚类技术旨在利用不同视图之间信息的互补性和一致性增强模型的鲁棒性,提高聚类准确率。本次报告首先讲述多视图聚类的基本概念,然后结合两篇算法对完全多视图聚类和不完全多视图聚类方法…

    2023年12月27日
    3.6K
  • 即时缺陷预测技术研究

    本报告讲述了即时软件缺陷预测领域的基本概念,通过详细介绍集成了专家特征和语义特征的变更级软件缺陷预测和缺陷定位模型,启发思考通过结合专家特征和代码行上下文语义特征,提高变更级软件缺…

    2022年12月13日
    3.5K
  • 基于协同过滤的推荐算法

          推荐系统在现在的生活中随处可见,淘宝天猫的商品推荐,音乐软件的每日歌曲推荐等,协同过滤就是一种很受欢迎的推荐…

    2018年8月27日
    3.2K
  • 预训练语言模型GPT3

    为了从网络上海量文本信息提取有价值信息,需要使用计算机处理文本数据,首要任务是将文本转换为计算机可以处理的向量化数据。单词是文本的最小单位,所以需要使用语言模型得到词向量表示成为文…

    2021年2月19日
    3.6K
  • 跨域开发与安全

    在大型项目开发时,可能会遇到多域名或多个ip之间使用ajax异步请求进行通信的情况,默认情况下,浏览器会阻断ajax对跨域请求的读取。本此报告介绍了开发中的跨域方案和跨域方案可能产…

    2020年9月14日
    3.6K
  • 程序崩溃的根本原因分析

    程序崩溃的根本原因分析技术旨在通过分析崩溃时的输入数据,自动推断并定位导致崩溃的根本原因所在的位置,辅助开发人员快速修复软件缺陷。本次报告介绍了2个利用谓词进行程序崩溃的根本原因分…

    2024年7月2日
    3.1K
  • 高准确率的鲁棒加密恶意流量实时检测方法

    本报告讲述了加密恶意流量检测领域基本概念,通过详细介绍基于频域分析的实时鲁棒恶意流量检测和基于自适应聚类的网络边缘恶意流量分类方法,启发思考通过统计聚类分析来提升加密恶意流量检测算…

    2022年3月21日
    3.8K
  • Android Hook 技术分析

      Hook技术就是在事件传送到终点前截获并监控事件的传输,像个钩子钩上事件一样,并且能够在钩上事件时,处理一些自己特定的事件。  附件-Android Hook 技术分析.pdf

    学术报告 2017年11月11日
    3.2K