动态规划

来源:互联网 发布:淘宝如何买发票 编辑:程序博客网 时间:2024/04/27 05:01
动态规划是,据说,最难的一类算法。确实,看起来也是非常的费劲;很多内容没看太明白,先总结一部分,然后再说吧。 

 

[概念]

1,和贪婪算法一样,在动态规划中,可将一个问题的解决方案视为一系列决策的结果。不同的是,在贪婪算法中,每采用一次贪婪准则便做出一个不可撤回的决策,而在动态规划中,还要考察每个最优决策序列中是否包含一个最优子序列。

 

2,当最优决策序列中包含最优决策子序列时,可建立动态规划递归方程(recurrence equation),它可以帮助我们高效地解决问题。根据我的理解,这个递归方程是整个动态规划问题的核心:如果可以制作递归方程,那么基本上就是可解的;如果不能构造出递归方程,则很难对这个问题实施可行性的解。

 

3,动态规划方法采用最优原则( principle of optimality)来建立用于计算最优解的递归式。所谓最优原则即不管前面的策略如何,此后的决策必须是基于当前状态(由上一次决策产生)的最优决策。由于对于有些问题的某些递归式来说并不一定能保证最优原则,因此在求解问题时有必要对它进行验证。若不能保持最优原则,则不可应用动态规划方法。在得到最优解的递归式之后,需要执行回溯以构造最优解。

 

4,使用递归程序来求解动态规划递归方程的时候,如果不避免重复计算,递归程序的复杂性将非常恐怖。所以,希望能够在递归程序设计中解决重复计算,或者使用迭代方式来求解,自然地避免了重复计算。如果没有了重复计算,复杂性将急剧下降。尽管迭代程序与避免重复计算的递归程序有相同的复杂性,但迭代程序不需要附加的递归栈空间,因此将比避免重复计算的递归程序更快。

 

[具体案例]

1,最短路经

a, 有向图,要寻找一条从源节点s= 1到目的节点d= 5的最短路径,即选择此路径所经过的各个节点。

b, 解释:最短路径问题中,假如在第一次决策时到达了某个节点v,那么不管v 是怎样确定的,此后选择从v 到d 的路径时,都必须采用最优策略。

 

2,0/1背包问题

a, 如前所述,在该问题中需要决定x1 .. xn的值。假设按i = 1,2,.,n 的次序来确定xi 的值。如果置x1 = 0,则问题转变为相对于其余物品(即物品2,3,.,n),背包容量仍为c 的背包问题。若置x1 = 1,问题就变为关于最大背包容量为c-w1 的问题。现设r={c,c-w1 } 为剩余的背包容量。

b, 解释:在这个问题中,第i个元素的值的选择(0或者1),不会影响后续n-i个元素的解;另外,刨除i之后,后面n-i个元素的最优解,必定是构成整个解的最优解的一部分。

c, 递归方程:

f(n,y) = p(n), if y>=w(n);

      or = 0, if y<w(n);

f(i,y)= max(f(i+1, y), f(i+1,y-w(i)) + p(i),  if y>=w(i);

    or = f(i+1,y), if y<w(i);

根据这个递归方程,很容易就能构造出来一个递归的代码(没有验证和调试):

  1. int f(int i, int j)
  2. {
  3.     if (i == n) return (y < w[n]) ? 0 : p[n];
  4.     if (y < w[n]) return f(i+1, y);
  5.     return max(f(i+1,y), f(i+1, y-w[i]) + p[i]);
  6. }

3,航费

4,图像压缩

5,所有点对的最短路径

 

6,矩阵乘法链

a, 一个m×n矩阵A与n×p矩阵B相乘需耗费O(m*n*p)的时间。(A*B) *C和A* (B*C) ,尽管这两种不同的计算顺序所得的结果相同,但时间消耗会有很大的差距。

b, 使用动态规划的方法,会期望把性能降低到O(q^3),q是矩阵个数。

c, 递归方程:

c(i,i) = 0 --> 1<=i<=q; c保存的是费用;

c(i, i+1)=r[i]*r[i+1]*r[i+2], 同时, kay(i, i+1) = i; --> 1<=i<=q;

c(i, i+s) = min(c(i, k) + c(k+1, i+s) + r[i]*r[k+1]*r[i+s+1],  --> 1<=i<=q-s, 1<s<q; k属于[i, i+s)累计

kay(i,j)保存的事从i到j中能够得到最小K的数据;

 

[矩阵乘法链代码]

  1. const int SIZE = 6;
  2. // matrix row and cols
  3. int r[SIZE] = {10, 5, 1, 10, 2, 10};
  4. // matrix mult order
  5. int kay[SIZE][SIZE] = {0};
  6. // avoid re-computing for cost
  7. int c[SIZE][SIZE] = {0};
  8. // calculate the min cost of:
  9. // M(i,k) X M(k,j)
  10. int cost(int i, int j) 
  11. {
  12.     if ( c[i][j] > 0)   //avoid re-computing for cost
  13.         return c[i][j];
  14.     if (i == j) // M(ii) need no time
  15.         return 0;
  16.     if (i == (j - 1)) { // M(i,i) X M(i+1,i+1) need: r(i)*r(i+1)*r(i+2)
  17.         kay[i][j] = i;
  18.         return c[i][j] = r[i]*r[i+1]*r[j+1];
  19.     }
  20.     // more than 2 matrices for mult
  21.     // set min u 
  22.     int u = cost(i, i) + cost(i + 1, j) + r[i]*r[i+1]*r[j+1];
  23.     kay[i][j] = i;
  24.     // compute the remain min term
  25.     for ( int k = i + 1; k < j; k++) {
  26.         int temp = cost(i, k) + cost(k + 1, j) + r[i]*r[k+1]*r[j+1];
  27.         if ( temp < u ) {
  28.             u = temp;
  29.             kay[i][j] = k;
  30.         }
  31.     }
  32.     c[i][j] = u;
  33.     return u;
  34. }
  35. // print result
  36. void printResult(int i, int j)
  37. {
  38.     if ( i == j ) 
  39.         return;
  40.     printResult(i, kay[i][j]);
  41.     printResult(kay[i][j] + 1, j);
  42.     printf("Multiply M[%d,%d]", i, kay[i][j]);
  43.     printf(" and M[%d,%d]/n", kay[i][j] + 1, j);
  44. }
  45. // test
  46. int main(int argc, char* argv[])
  47. {
  48.     cost(0, SIZE - 2);
  49.     printResult(0, SIZE - 2);
  50.     getchar();
  51.     return 0;
  52. }

[其他]

待扩展

原创粉丝点击