动态规划之最长公共子序列
Posted dalgleish
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态规划之最长公共子序列相关的知识,希望对你有一定的参考价值。
原理请参考《算法导论》
定义常量
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\\n", 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\\n",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("\\n优化后的代码...\\n"); printf("Max %d\\n", lcsLength1(A, B, LENGTHA, LENGTHB, &c)); lcsprintf(c, LENGTHA + 1, LENGTHB + 1); lcsprintf1(c, A, B, LENGTHA, LENGTHB); printf("\\n打印所有可能\\n"); 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("\\n"); } printf("\\n"); } void lcsfree(int **p, int n) { for (int i = 0; i < n; i++) delete[] p[i]; delete[] p; }
打印结果:
所有代码均经过测试,结果正确。
以上是关于动态规划之最长公共子序列的主要内容,如果未能解决你的问题,请参考以下文章