zoukankan      html  css  js  c++  java
  • 动态规划之最长公共子序列

    原理请参考《算法导论》

    定义常量

    enum {upper_left, up, left};
    #define LENGTHA (sizeof(A)/sizeof(A[0]))
    #define LENGTHB (sizeof(B)/sizeof(B[0]))

    版本1,带辅助数组b

    int lcsLength(int *A, int *B, int m, int n, int ***c, int ***b) {
        int i, j;
        if (m <= 0 || n <= 0) return -1;
        *c = new int *[m + 1];
        *b = new int *[m + 1];
        for (int i = 0; i <= m; i++) {
            (*c)[i] = new int[n + 1];
            (*b)[i] = new int[n + 1];
        }
        //初始化边界
        for (i = 1; i <= m; i++)
            (*b)[i][0] = (*c)[i][0] = 0;
        for (j = 0; j <= n; j++)
            (*b)[0][j] = (*c)[0][j] = 0;
        for (i = 1; i <= m; i++)
            for (j = 1; j <= n; j++) {
                if (A[i - 1] == B[j - 1]) {
                    (*c)[i][j] = (*c)[i - 1][j - 1] + 1;
                    (*b)[i][j] = upper_left;
                }
                else {
                    if ((*c)[i - 1][j] >= (*c)[i][j - 1]) {
                        (*c)[i][j] = (*c)[i - 1][j];
                        (*b)[i][j] = up;
                    }
                    else {
                        (*c)[i][j] = (*c)[i][j - 1];
                        (*b)[i][j] = left;
                    }
                }
            }
        return (*c)[m][n];
    }

    对应输出函数

    void lcsprintf(int **b, int *A, int i, int j) {
        if (i == 0 || j == 0) return;
        if (b[i][j] == upper_left) {
            lcsprintf(b, A, i - 1, j - 1);
            printf("%C ", A[i-1]);
        }
        else if (b[i][j] == up)
            lcsprintf(b, A, i - 1, j);
        else
            lcsprintf(b, A, i, j - 1);
    }

    版本2,不带辅助数组b

    int lcsLength1(int *A, int *B, int m, int n, int ***c) {
        int i, j;
        if (m <= 0 || n <= 0) return -1;
        *c = new int *[m + 1];
        for (int i = 0; i <= m; i++) 
            (*c)[i] = new int[n + 1];
        //初始化边界
        for (i = 1; i <= m; i++)
            (*c)[i][0] = 0;
        for (j = 0; j <= n; j++)
            (*c)[0][j] = 0;
        for (i = 1; i <= m; i++)
            for (j = 1; j <= n; j++) {
                if (A[i - 1] == B[j - 1]) 
                    (*c)[i][j] = (*c)[i - 1][j - 1] + 1;
                else {
                    if ((*c)[i - 1][j] >= (*c)[i][j - 1]) 
                        (*c)[i][j] = (*c)[i - 1][j];
                    else 
                        (*c)[i][j] = (*c)[i][j - 1];
                }
            }
        return (*c)[m][n];
    }

    对应输出函数

    void lcsprintf1(int **c, int *A,int *B, int i, int j) {
        if (i==0 || j == 0) return;
        if (A[i - 1] == B[j - 1]) {
                lcsprintf1(c, A, B, i - 1, j - 1);
                printf("%C ", A[i-1]);
        }
        else {
            if (c[i - 1][j] >= c[i][j - 1])
                lcsprintf1(c, A, B, i - 1, j);
            else
                lcsprintf1(c, A, B, i, j - 1);
        }
    }

    最后,打印所有可能函数

    void lcsprintfAll(int **c, int *A, int *B, int i, int j, std::string str) {
        while (i > 0 && j > 0) {
            if (A[i - 1] == B[j - 1]) {
                str = (char)A[i - 1] + (" " + str);
                i--; 
                j--;
            }
            else {
                if (c[i - 1][j] > c[i][j - 1]) //向左走  
                    i--;
                else if (c[i - 1][j] < c[i][j - 1]) //向上走  
                    j--;
                else {
                    lcsprintfAll(c, A, B, i - 1, j, str);
                    lcsprintfAll(c, A, B, i, j - 1, str);
                    return;
                }
            }
        }
        printf("%s
    ", str.c_str());
    }

    Main函数

    int main()
    {
        int A[] = { 'A','B','C','B','D','A','B' }, B[] = {'B','D','C','A','B','A' };
        int **c, **b;
        printf("Max %d
    ",lcsLength(A, B, LENGTHA, LENGTHB, &c, &b));
        lcsprintf(c, LENGTHA + 1, LENGTHB + 1);//多申请了一个边界
        lcsprintf(b, LENGTHA + 1, LENGTHB + 1);
        lcsprintf(b, A, LENGTHA, LENGTHB);
        lcsfree(c, LENGTHA + 1);
        lcsfree(b, LENGTHA + 1);
        printf("
    优化后的代码...
    ");
        printf("Max %d
    ", lcsLength1(A, B, LENGTHA, LENGTHB, &c));
        lcsprintf(c, LENGTHA + 1, LENGTHB + 1);
        lcsprintf1(c, A, B, LENGTHA, LENGTHB);
        printf("
    打印所有可能
    ");
        std::string str;
        lcsprintfAll(c, A, B, LENGTHA, LENGTHB, str);
        lcsfree(c, LENGTHA + 1);
        return 0;
    }
    //A: 'A','B','C','B','D','A','B'
    //B: 'B','D','C','A','B','A'

    辅助函数

    void lcsprintf(int **b, int m, int n) {
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++)
                printf("%04d  ", b[i][j]);
            printf("
    ");
        }
        printf("
    ");
    }
    
    void lcsfree(int **p, int n) {
        for (int i = 0; i < n; i++)
            delete[] p[i];
        delete[] p;
    }

    打印结果:

    所有代码均经过测试,结果正确。

  • 相关阅读:
    cxGrid 锁定列
    精选网站
    Delphi XE10 dxLayoutControl 控件应用指南
    合并当前工作簿下的所有工作表
    【集中工作薄】 当前文件夹中所有Excel文件中 多个工作簿的第一个工作表 复制到工作簿中
    CxGrid如何实现导出Excel 功能
    Google Material Design的图标字体使用教程
    Mui沉浸模式以及状态栏颜色改变
    移动端弹性效果
    JS中的“!!”
  • 原文地址:https://www.cnblogs.com/dalgleish/p/9131530.html
Copyright © 2011-2022 走看看