第3章学习小结
Posted c-ch3-5
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第3章学习小结相关的知识,希望对你有一定的参考价值。
动态规划 —— 经分解得到的子问题往往不是互相独立的
一、基本思想:保存已解决的子问题的答案,在需要时再找出已求得的答案,这样可以避免大量的重复计算,从而得到多项式时间算法。为了达到此目的,可以用一个表来记录所有已解 决的子问题的答案,不管该子问题以后是否被用到,只要它被计算过就将其结果填入表中。
1、设计步骤:①找出最优解的性质并刻划其结构特征 ②递归的定义最优值
③以自底向上的方式计算最优值 ④根据计算最优值时得到的信息,构造最优解
二、矩阵连乘问题
1、分析最优解结构
计算 A[1:n] 的最优次序所包含的计算矩阵子链 A[1:k] 和 A[k+1:n] 的次序也是最优的。事实上,如果计算 A[1:k] 的次序需要的计算量更少,则用此次序替换原来计算 A[1:k] 的次序,得到的计算 A[1:n] 的计算 量将比最优次序所需计算量更少,这是一个矛盾。同理可知,计算 A[1:n] 的最优次序包含的计算矩阵子链 A[k+1:n] 的次序也是最优的。因此,矩阵连乘积计算次序问题的最优解包含着其子问题的最优解。这种 性质称为最优子结构性质。问题的最优子结构性质是该问题可用动态规划算法求解的显著特征。
2、建立递归关系
m[i][j]={ 0 i=j / min{m[i][k] + m[k+1][j] + Pi-1 Pk Pj i<j (其中 i ≤ k ≤ j)
若将对应的 m[i][j] 的断开位置 k 记为 s[i][j] ,在计算出最优值 m[i][j] 后,可递归地由 s[i][j] 构造出相应的最优解
3、计算最优值
void MatrixChain(int *p,int n,int **m,int **s) { for(int i=1;i<=n;i++) m[i][j]=0; for(int r=2;r<=n;r++) { for(int i=1;i<=n-r+1;i++) { int j=i+r-1; m[i][j]=m[i+1][j]+p[i-1]*p[i]*p[j]; s[i][j]=i; for(int k=i+1;k<j;k++) { int t=m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j]; if(t<m[i][j]) { m[i][j]=t; s[i][j]=k; } } } } }
4、构造最优解
三、动态规划算法的基本要素
1、最优子结构。当问题的最优解包含了其子问题的最优解时,称该问题具有最优子结构性质。在动态规划算法中,利用问题的最优子结构性质,以自底向上的方式,递归地从子问题的最优解逐步构造出整 个问题的最优解。
2、重叠子问题。在用递归算法自顶向下解此问题时,每次产生的子问题并不总是新问题,有些子问题被反复计算。动态规划算法利用了这种子问题的重叠性质,对每个子问题只解一次,然后将其解保存在一个表 格中,当再次需要解此子问题时,只是简单地用常数时间查看一下结果。通常,不同的子问题个数随问题的大小呈多项式增长。因此,用动态规划算法通常只需要多项式时间,从而获得较高的解题效率。
四、最长公共子序列
用 c[i][j] 记录序列 Xi 和 Yi 的最长公共子序列长度
0 i>0; j=0
c[i][j]= c[i-1][j-1] + 1 i,j>0; xi = yi
max {c[i][j-1],c[i-1][j] i,j>0; xi ≠ yi
void LCSLength(int m,int n,char *x,char *y,int **c,int **b) { int i,j; for(i=1;i<=m;i++) c[i][0]=0; for(i=1;i<=n;i++) c[0][i]=0; for(i=1;i<=m;i++) { for(j=1;j<=n;++j) { if(x[i]==y[j]) { 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]; } } } }
五、0-1 背包问题
maxΣ vi xi { Σ wi xi ≤ c
xi ∈ {0,1} 1 ≤ i ≤ n
0-1背包问题的子问题的最优值为m(i,j),即m(i,j)是背包容量为j,可选择物品为i,i+1,……,n时,0-1背包问题的最优值。原始问题m(1,c)
递归式 m(i,j)= max{m(i + 1, j), m(i + 1, j - wj) + vi} j≤wi ( 第 i 个物品可以放得下,权衡放不放)
{ m(i + 1 , j) 0≤ j ≤ wn (第 i 个物品放不下,wi > j )
m(n,j)={ vn j ≥ wn / 0 0 ≤ j ≤ wn
void knapsack(Type v,int w,int c,int n,Type **m) {//自底向上填表 int jMax=min(w[n]-1,c); //第n行 for(int j=0;j<=jMax;j++) //放不下 m[n][j]=0; for(int j=w[n];j<=c;j++) //开始放得下 m[n][j]=v[n]; for(int i=n-1;i>1;--i) //第2~n-1行,第i行:当前物品 { jMax=min(w[i]-1,c); for(int j=0;j<=jMax;j++) //放不下 m[i][j]=m[i+1][j]; for(int j=w[i];j<=c;j++) //放 m[i][j]=max(m[i+1][j],m[i+1][j-w[i]]+v[i]); } m[1][c]=m[2][c]; if(c>=w[1]) m[1][c]=max(m[1][c],m[2][c-w[1]]+v[1]); }
以上是关于第3章学习小结的主要内容,如果未能解决你的问题,请参考以下文章