动态规划法(一)

来源:互联网 发布:数据魔方为什么下线 编辑:程序博客网 时间:2024/06/05 11:50

一、引言

       “动态规划” (dynamic programming)一词源于研究优化问题的数学理论,动态规划法的发明人贝尔曼(Richard E.Bellman)称,选择“dynamic”一词纯粹是看中了单词本身的魅力,而不是其内在语义。“programming”在研究优化的领域中标识“搜寻最优程序”的意思。


1、重复子问题

     大体上,动态规划法与分治法具有类似的处理方式。使用动态规划法的算法通常先把问题分割成若干子问题,然后求出子问题的答案,最后利用这些答案得出整个问题的最终答案。在动态规划法中,一些子问题的计算结果会用于多个问题的解题过程。因此,在对子问题进行一次计算的情况下,重复利用其结果。为了实现这种方法,需将子问题的答案预先保存到内存,这种保存答案的内存区域就是“缓存”(cache),能够重复利用两次以上的子问题就称为 “重复子问题”。

/*应用 动态规划法 的最有名的事例之一就是二项式系数的计算根据二项式系数有如下递归式Cn取r等于Cn-1取r-1加上Cn-1取r */#include <iostream>using namespace std;int bino(int n,int r){if(r==0 || r==n)return 1;return bino(n-1,r-1) + bino(n-1,r);}int main(){int n,r;cout<<"请输入二项式系数n,r"<<endl;cin>>n>>r;bino(n,r);//利用递归调用计算二项式系数cout<<bino(n,r)<<endl;system("pause");return 0;}

       bino()内部没有任何循环,因此,可通过计算递归调用的次数来估计bino(n,r)的执行时间,此时需要注意的是,二项式系数的特性会导致很多重复计算。函数的重复调用次数会随着n和r值的增大而呈几何级数增长。如果要计算bino(25,12),就要调用一千万次函数。因此需要想办法避开这些重复计算。当输入值n和r一定的时候,bino(n,r)的返回值也是一定的,利用此原理就可以去掉重复计算。首先定义一个缓存数组,用来保存对不同的n、r组合计算出的结果。每次调用函数时先访问缓存数组,查询有没有相应的结果值,如果有,就返回数组中的值,否则直接计算,计算结果先保存到数组,然后再返回。

      像这种先定义保存函数结果值的空间,然后重复使用结果值的优化方法称为制表。下面代码演示了利用制表计算二项式系数:

/*应用 动态规划法 的最有名的事例之一就是二项式系数的计算根据二项式系数有如下递归式Cn取r等于Cn-1取r-1加上Cn-1取r*/#include <iostream>#define MAX 100using namespace std;int cache[MAX][MAX];//缓存区域用于存储函数结果值,并初始化为-1int bino2(int n, int r){if (r == 0 || r == n)return 1;if (cache[n][r] != -1)return cache[n][r];return cache[n][r] = bino2(n - 1, r - 1) + bino2(n - 1, r);//直接计算并保存到数组}int main(){int n, r;int i, j;for (i = 0; i < MAX; i++){for (j = 0; j < MAX; j++)cache[i][j] = -1;  //初始化为-1}cout << "请输入二项式系数n,r" << endl;cin >> n >> r;bino2(n, r);//利用制表计算二项式系数cout << bino2(n, r) << endl;system("pause");return 0;}


0 0