动态规划
2008-12-08 14:13
134 查看
动态规划是,据说,最难的一类算法。确实,看起来也是非常的费劲;很多内容没看太明白,先总结一部分,然后再说吧。
[概念]
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);
根据这个递归方程,很容易就能构造出来一个递归的代码(没有验证和调试):
int f(int i, int j)
{
if (i == n) return (y < w
) ? 0 : p
;
if (y < w
) return f(i+1, y);
return max(f(i+1,y), f(i+1, y-w[i]) + p[i]);
}
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的数据;
[矩阵乘法链代码]
const int SIZE = 6;
// matrix row and cols
int r[SIZE] = {10, 5, 1, 10, 2, 10};
// matrix mult order
int kay[SIZE][SIZE] = {0};
// avoid re-computing for cost
int c[SIZE][SIZE] = {0};
// calculate the min cost of:
// M(i,k) X M(k,j)
int cost(int i, int j)
{
if ( c[i][j] > 0) //avoid re-computing for cost
return c[i][j];
if (i == j) // M(ii) need no time
return 0;
if (i == (j - 1)) { // M(i,i) X M(i+1,i+1) need: r(i)*r(i+1)*r(i+2)
kay[i][j] = i;
return c[i][j] = r[i]*r[i+1]*r[j+1];
}
// more than 2 matrices for mult
// set min u
int u = cost(i, i) + cost(i + 1, j) + r[i]*r[i+1]*r[j+1];
kay[i][j] = i;
// compute the remain min term
for ( int k = i + 1; k < j; k++) {
int temp = cost(i, k) + cost(k + 1, j) + r[i]*r[k+1]*r[j+1];
if ( temp < u ) {
u = temp;
kay[i][j] = k;
}
}
c[i][j] = u;
return u;
}
// print result
void printResult(int i, int j)
{
if ( i == j )
return;
printResult(i, kay[i][j]);
printResult(kay[i][j] + 1, j);
printf("Multiply M[%d,%d]", i, kay[i][j]);
printf(" and M[%d,%d]/n", kay[i][j] + 1, j);
}
// test
int main(int argc, char* argv[])
{
cost(0, SIZE - 2);
printResult(0, SIZE - 2);
getchar();
return 0;
}
[其他]
待扩展
[概念]
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);
根据这个递归方程,很容易就能构造出来一个递归的代码(没有验证和调试):
int f(int i, int j)
{
if (i == n) return (y < w
) ? 0 : p
;
if (y < w
) return f(i+1, y);
return max(f(i+1,y), f(i+1, y-w[i]) + p[i]);
}
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的数据;
[矩阵乘法链代码]
const int SIZE = 6;
// matrix row and cols
int r[SIZE] = {10, 5, 1, 10, 2, 10};
// matrix mult order
int kay[SIZE][SIZE] = {0};
// avoid re-computing for cost
int c[SIZE][SIZE] = {0};
// calculate the min cost of:
// M(i,k) X M(k,j)
int cost(int i, int j)
{
if ( c[i][j] > 0) //avoid re-computing for cost
return c[i][j];
if (i == j) // M(ii) need no time
return 0;
if (i == (j - 1)) { // M(i,i) X M(i+1,i+1) need: r(i)*r(i+1)*r(i+2)
kay[i][j] = i;
return c[i][j] = r[i]*r[i+1]*r[j+1];
}
// more than 2 matrices for mult
// set min u
int u = cost(i, i) + cost(i + 1, j) + r[i]*r[i+1]*r[j+1];
kay[i][j] = i;
// compute the remain min term
for ( int k = i + 1; k < j; k++) {
int temp = cost(i, k) + cost(k + 1, j) + r[i]*r[k+1]*r[j+1];
if ( temp < u ) {
u = temp;
kay[i][j] = k;
}
}
c[i][j] = u;
return u;
}
// print result
void printResult(int i, int j)
{
if ( i == j )
return;
printResult(i, kay[i][j]);
printResult(kay[i][j] + 1, j);
printf("Multiply M[%d,%d]", i, kay[i][j]);
printf(" and M[%d,%d]/n", kay[i][j] + 1, j);
}
// test
int main(int argc, char* argv[])
{
cost(0, SIZE - 2);
printResult(0, SIZE - 2);
getchar();
return 0;
}
[其他]
待扩展
相关文章推荐
- 动态规划——最大子段和问题
- 斐波那契系列问题的递归和动态规划
- 动态规划---LIS
- 斐波那契系列问题的递归和动态规划2
- 动态规划-最优二分检索树
- 复制书稿(动态规划,贪心算法)
- 0019算法笔记——【动态规划】0-1背包问题
- 【BZOJ4872】分手是祝愿(动态规划,数学期望)
- 动态规划(练习题目,)
- Leetcode 70. Climbing Stairs 爬楼梯 (递归,记忆化,动态规划)
- 多重背包,多种解法,动态规划
- 【2018寒假集训 Day2】【动态规划】回文字
- hdu2069Coin Change(暴力求解----动态规划(背包)求解---搜索--)
- 【BZOJ3992】序列统计(动态规划,NTT)
- 整数划分问题(动态规划)
- 【Luogu1291】百事世界杯之旅(动态规划,数学期望)
- 最短编辑距离-动态规划
- 【BZOJ2442】修建草坪(动态规划,单调队列)
- poj-1322-Chocolate 使用动态规划求解的一种概率问题的算法
- 动态规划解决最长公共序列