zoukankan      html  css  js  c++  java
  • poj 3356 AGTC(线性dp)

    题目链接:http://poj.org/problem?id=3356

    思路分析:题目为经典的编辑距离问题,其实质为动态规划问题;

    编辑距离问题定义:给定一个字符串source,可以对其进行复制,替换,删除,增加操作,另外根据具体情况已经规定了每种操作的cost,现在要求求出一个操作序列,使其变为一个给定的字符串dest,并且该操作序列的cost的和最小(在该题目中复制开销为0,其他开销为1);

    该问题为动态规划问题,先对该问题进行分析:

    1)发掘最优子结构:

    假设源字符串为S[0, 1, 2,..,n-1],其长度为n,目标字符串为D[0, 1, 2, ...., m-1],长度为m,则该问题转换为求一个cost最小的操作序列将

    S[0,1,2,...,n-1]转换为D[0, 1, 2, ...., m-1];先考虑如何将S[0]转换为D[0];为了将S[0]转换为D[0],我们先选择一个操作,假设该操作是产生最

    优的操作序列的第一个操作,这样我们就能将S[0]转换为D[0],则原来的问题在该操作后产生了一个子问题(在不同的动态规划问题中可能会产

    生不同的子问题个数),即求一个cost最小的操作序列将S[1, 2, ... , n-1]转换为D[1, 2, ..., m-1],我们可以证明该子问题的最优解可以构造出原

    来问题的最优解,这样我们就发现了该问题的最优子结构;另外,我们还需要考虑第一步的选择有多少种(不同动态规划问题的选择的可能性的

    种类数目不同),即将S[0]转换为D[0]可以有多少种操作方法,明显在这个问题中有4种;

    2)重叠子问题

    如果该问题的递归算法反复地求解子问题,那么我们就称该最优化问题具有重叠子问题性质;在分治算法中,递归算法会生成全新的子问题,

    子问题与子问题之间是无关的;而动态规划算法不同,如求斐波那契数列的递归算法中求数列f[n]需要求解f[n-1]与f[n-2],而f[n-1]=f[n-2]+f[n-3],

    可以看到,在求斐波那契数列的递归算法中f[n-2]被求解多次,则求具有重叠子问题的结构,但是求斐波那契数列算法不是动态规划算法,因为其

    不具有最优子结构,这里提出该问题是让大家对重叠子问题有一个具体的认识;现在,我们可以明显看到,在求解编辑距离问题中,我们做出一次

    选择,就会产生一个子问题,因为在每一步中我们可能会做出多个选择,所以会求解多个相同的子问题,如在第一步中,我们可以选择复制(如果

    S[0]==D[0]),删除,替换,增加操作,每个选择的操作就会产生相同的子问题,即求解S[1,2, .., m]转换D[1, 2, ..., n]的最小的cost的操作序列;

    所以该问题具有重叠子问题;

    3)解法:

    对于该问题,我们刻画该问题的问题空间:假设dp[i][j]表示从字符串S[i, i+1, i+2, ...., m-1]转换为字符串D[j, j+1, j+2, ...., n-1]的操作序列的最小的cost和,

    则原问题为求dp[0][0];

    对于特殊的情况:

    dp[i, n] = m-i,表示使S[i, i+1, ...,m-1]转换为空字符串,只能删除m-i个字符,所以最小的cost和为m-i;

    dp[m, j] = n-j,表示使空字符串转换为D[j, j+1, ..., n-1],则只能增加n-j个字符,所以最小的cost和为n-j;

    关于选择的可能:

    <1>复制:dp[i, j] = dp[i+1, j+1], 如果S[i]==D[j],可以使用复制操作;

    <2>删除:dp[i, j] = dp[i+1, j] + 1,删除操作cost为1,删除S[i],子问题为dp[i+1, j];

    <3>替换:dp[i, j] = dp[i+1, j+1] + 1,替换操作只能在S[i]与D[j]不相等时才能选择;

    <4>增加:dp[i, j] = dp[i, j+1] + 1,同样的,增加操作cost为1;

    则该问题的动态规划方程已经给出,可以求解该问题;

    代码如下:

    #include <cstdio>
    #include <iostream>
    using namespace std;
    
    const int MAX_N = 1000 + 10;
    char source[MAX_N], dest[MAX_N];
    int dp[MAX_N][MAX_N];
    
    inline int Min(int a, int b) { return a > b ? b : a; }
    
    int main()
    {
        int s_len, d_len;
    
        while(scanf("%d %s", &s_len, source) != EOF)
        {
            scanf("%d %s", &d_len, dest);
    
            memset(dp, 0, sizeof(dp));
            for (int i = 0; i <= d_len; ++i)
                dp[s_len][i] = d_len - i;
            for (int i = 0; i <= s_len; ++i)
                dp[i][d_len] = s_len - i;
            for (int i = s_len - 1; i >= 0; --i)
            {
                for (int j = d_len - 1; j >= 0; --j)
                {
                    int min_cost = 100000;
    
                    min_cost = Min(min_cost, dp[i + 1][j] + 1);
                    min_cost = Min(min_cost, dp[i][j + 1] + 1);
                    if (source[i] == dest[j])
                        min_cost = Min(min_cost, dp[i + 1][j + 1]);
                    else
                        min_cost = Min(min_cost, dp[i + 1][j + 1] + 1);
                    dp[i][j] = min_cost;
                }
            }
            printf("%d
    ", dp[0][0]);
        }
    
        return 0;
    }
  • 相关阅读:
    verilog parameter 位宽问题
    quartus prime 16.0 报警告 inferring latch
    Quartus prime16.0 组合逻辑always块中敏感向量表不全
    centos6.8下安装matlab2009(图片转帖)
    centos6.8下普通用户下quartus编程识别不到用户开发板
    centos6.8下安装破解quartus prime16.0以及modelsim ae安装
    PHP TP 生成二维码
    模态框MODAL的一些事件捕捉
    iOS微信第三方登录实现
    PHP ini 配置无效的坑给自己记录
  • 原文地址:https://www.cnblogs.com/tallisHe/p/4521162.html
Copyright © 2011-2022 走看看