[关闭]
@Alllll0235 2017-08-08T14:21:09.000000Z 字数 6689 阅读 979

Dynamic programming

learning


A dynamic-programming algorithm solves each subsubproblem just once and then saves its answer in a table, thereby avoiding the work of recomputing the answer every time it solves each subsubproblem.

steps:

  1. Characterize the structure of an optimal solution.
  2. Recursively define the value of an optimal solution.
  3. Compute the value of an optimal solution, typically in a bottom-up fashion.
  4. Construct an optimal solution from computed information.

Example 1 Rod cutting

Given a rod of length n inches and a table of prices for ,determine the maximum revenue obtainable by cutting up the rod and selling the prices.

长度i 1 2 3 4 5 6 7 8 9 10
价格 1 5 8 9 10 17 17 20 24 30

maximum revenue

Recursive top-down implementation

  1. static int k=0;
  2. int cutrod(int p[],int n)
  3. //p为每个长度的价格,n为长度
  4. //q为输出,保存每个长度的最优价格
  5. {
  6. if(n==0)
  7. return 0;
  8. int q=0;
  9. for(int i=0;i<n;i++)
  10. q=MAX(q,p[i]+cutrod(p,n-i-1));
  11. k++;
  12. cout<<q<<" ";//输入每次调用函数保存的最优价格
  13. return q;
  14. }

输出结果:

enter the length of steer:4
1 5 1 8 1 5 1 10 
the times of recursion:8

CUT-ROD calls itself recursively over and over again with the same parameter value; it solves the same subproblems repeatedly.

top-down with memoization

  1. static int k=0;
  2. int memoized_cut_rod_aux(int p[],int n,int r[])
  3. {
  4. if (r[n]>=0)
  5. return r[n];
  6. int q;
  7. if (n==0)
  8. q=0;
  9. else
  10. {
  11. q=-1;
  12. for(int i=0;i<n;i++)
  13. q=max(q,p[i]+memoized_cut_rod_aux(p,n-i-1,r));
  14. }
  15. r[n]=q; //保存子问题的解
  16. k++; //计算递归次数
  17. cout<<q<<" ";
  18. return q;
  19. }
  20. int memoized_cut_rod(int p[],int n)
  21. {
  22. int *r=new int [n+1];
  23. for(int i=0;i<=n;i++)
  24. r[i]=-1;
  25. return memoized_cut_rod_aux(p,n,r);
  26. }

输出结果:

enter the length of steer:4
0  1  5  8  10  
the times of recursion:5

bottom-up method

  1. int bottom_up_cut_rod(int p[],int n)
  2. {
  3. int *r=new int [n+1];
  4. r[0]=0;
  5. for(int j=1;j<=n;j++)
  6. {
  7. int q=-1;
  8. for(int i=0;i<j;i++)
  9. q=max(q,p[i]+r[j-i-1]);
  10. r[j]=q;
  11. }
  12. return r[n];
  13. }

输出结果:

enter the length of steer:4
the maximum revenue:10

example 2 matrix chain

Given a sequence (chain) of n matrix to be multiplied, and we wish to compute the product .

  1. void Matrix_Chain_Order(int* p,int **m,int** s)
  2. {
  3. //矩阵链的长度
  4. int n = sizeof(p)/sizeof(p[0])-1;
  5. //①将对角线上的值先赋值为0
  6. for (int i = 1; i <= n; i++)
  7. {
  8. m[i][i] = 0;
  9. }
  10. int l = 0; //l为矩阵链的长度
  11. //m[i][j]的第一个参数
  12. int i = 0;
  13. //m[i][j]的第二个参数
  14. int j = 0;
  15. //②以长度L为划分,L从2开始到n
  16. for (l = 2; l <= n; l++)
  17. {
  18. //循环第一个参数,因为l的长度至少为2,所以i和j在这个循环里面肯定不相等
  19. for (i = 1; i <= n - l + 1; i++)
  20. {
  21. //因为j-i+1=l,所以j=l+i-1
  22. j = i + l - 1;
  23. //对于每个特定的i和j的组合,遍历此时所有的合适k值,k大于等于i小于j
  24. for (int k = i ; k < j; k++)
  25. {
  26. //这里k不能等于j,因为后面要m[k+1][j],不然k+1就比j大了
  27. int q = m[i][k] + m[k + 1][j] + p[i - 1] * p[k] * p[j];
  28. if (q < m[i][j])
  29. {
  30. m[i][j] = q;
  31. s[i][j] = k;
  32. }
  33. }
  34. }
  35. }
  36. }
  1. void print_optimal_parens(int** s, int i, int j)
  2. {
  3. if (i == j)
  4. {
  5. cout << "A" << i;
  6. }
  7. else
  8. {
  9. cout << "(";
  10. print_optimal_parens(s, i, s[i][j]);
  11. print_optimal_parens(s, s[i][j] + 1, j);
  12. cout << ")";
  13. }
  14. }

example 3 Longest common subsequence

Given two sequences and and wish to find maximumlength common subsequence of X and Y.

  1. void LCSLength(int m,int n,char *x,char *y,int **c,int **b)
  2. {
  3. //x和y是目标序列
  4. //m是x的长度,n是y的长度
  5. int i,j;
  6. //当x或y为空序列时,无公共子序列
  7. for(i=1; i<=m; i++) //x长度为i,y长度为j
  8. c[i][0] = 0;
  9. for(i=1; i<=n; i++)
  10. c[0][i] = 0;
  11. for(i=1; i<=m; i++)
  12. {
  13. for(j=1; j<=n; j++)
  14. {
  15. if(x[i]==y[j])
  16. {
  17. c[i][j]=c[i-1][j-1]+1;
  18. b[i][j]=1;
  19. }
  20. else if(c[i-1][j]>=c[i][j-1])
  21. {
  22. c[i][j]=c[i-1][j];
  23. b[i][j]=2;
  24. }
  25. else
  26. {
  27. c[i][j]=c[i][j-1];
  28. b[i][j]=3;
  29. }
  30. }
  31. }
  32. }
  1. void LCS(int i,int j,char *x,int **b)
  2. {
  3. if(i==0 || j==0)
  4. {
  5. return;
  6. }
  7. if(b[i][j]==1)
  8. {
  9. LCS(i-1,j-1,x,b);
  10. cout<<x[i]<<" ";
  11. }
  12. else if(b[i][j]==2)
  13. {
  14. LCS(i-1,j,x,b);
  15. }
  16. else
  17. {
  18. LCS(i,j-1,x,b);
  19. }
  20. }

Improving the code

  1. int LCS(string sx, string sy)
  2. {
  3. int sizex = sx.length();
  4. int sizey = sy.length();
  5. //创建动态二维数组
  6. int **lcs = new int*[sizex];
  7. for (int i = 0; i < sizex; i++)
  8. {
  9. lcs[i] = new int[sizey];
  10. }
  11. //求解LCS
  12. int max = 0;
  13. for (int i = 0; i < sizex; i++)
  14. {
  15. for (int j = 0; j < sizey; j++)
  16. {
  17. //计算初始值:lcs[0][x]和lcs[x][0]的值
  18. if (i == 0 || j == 0)
  19. {
  20. if (sx[i] == sy[j])
  21. {
  22. lcs[i][j] = 1;
  23. }
  24. else
  25. {
  26. if (i == 0 && j == 0)
  27. lcs[i][j] = 0;
  28. else if (i == 0 && j != 0)
  29. lcs[i][j] = lcs[i][j-1];
  30. else
  31. lcs[i][j] = lcs[i-1][j];
  32. }
  33. }
  34. else //其他lcs[i][j]的值
  35. {
  36. if (sx[i] == sy[j])
  37. lcs[i][j] = lcs[i-1][j-1] + 1;
  38. else
  39. lcs[i][j] = lcs[i-1][j] > lcs[i][j-1] ? lcs[i-1][j] : lcs[i][j-1];
  40. }
  41. if (lcs[i][j] > max)
  42. max = lcs[i][j];
  43. }
  44. }
  45. //释放动态二维数组
  46. for (int i = 0; i < sizex; ++i)
  47. {
  48. delete[] lcs[i];
  49. }
  50. delete[] lcs;
  51. return max;
  52. }

example 4 Optimal binary search trees

searchtree

0 1 2 3 4 5
0.15 0.10 0.05 0.10 0.20
0.05 0.10 0.05 0.05 0.05 0.10

: key
: the probability of
: the dummy key which represents all values between and
: the probability of

Every search is either successful (finding some key ) or unsuccessful (findng some dummy key ).

E [Search cost in T}

  1. copy
  2. void OPTIMAL_BST(int *p,int *q,int n,int **e,int **w,int **root)
  3. {
  4. //初始化只包含虚拟键的子树
  5. for(int i=1;i<=n+1;i++)
  6. {
  7. e[i][i-1]=q[i-1];
  8. w[i][i-1]=q[i-1];
  9. }
  10. for(int l=1;l<=n;l++)
  11. {
  12. for(int i=1;i<=n-l+1;i++)
  13. {
  14. j=i+l-1;
  15. e[i][j]=INT_MAX;
  16. w[i][j]=w[i][j-1]+p[i]+q[j]; //字数期望概率总和
  17. for(int r=i;r<=j;r++)
  18. {
  19. int t=e[i][r-1]+e[r+1][j]+w[i][j];
  20. if(t<e[i][j])
  21. {
  22. e[i][j]=t; //字数期望代价
  23. root[i][j]=r; //记录根节点
  24. }
  25. }
  26. }
  27. }
  28. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注