当前位置:编程学习 > 网站相关 >>

算法系列总结:动态规划

理论辅助:    

     动态规划算法通常用于求解具有某种最优性质的问题。在这类问题中,可能会有许多可行解。每一个解都对应于一个值,我们希望找到具有最优值的解。动态规划算法与分治法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。与分治法不同的是,适合于用动态规划求解的问题,经分解得到子问题往往不是互相独立的。若用分治法来解这类问题,则分解得到的子问题数目太多,有些子问题被重复计算了很多次。如果我们能够保存已解决的子问题的答案,而在需要时再找出已求得的答案,这样就可以避免大量的重复计算,节省时间。我们可以用一个表来记录所有已解的子问题的答案。不管该子问题以后是否被用到,只要它被计算过,就将其结果填入表中。这就是动态规划法的基本思路。具体的动态规划算法多种多样,但它们具有相同的填表格式。

     上面这段定义文字是我Copy过来的,目前我还没有那么好的总结能力,呵呵,如果大家对于动态规划不是很熟悉的话,可能看着上面一段文字会不知所云,我一般的学习方法是首先扫描一下基本定义,不深究(有点不求甚解的味道),然后去看一些实例,结合自己的体会,最后再回顾,精读一下定义,这样我对定义才能够真正的理解。下面我们依托一个经典的算法问题来体现上面这段文字的思想,0-1背包问题在算法学习中可谓是必修课程,一般在讲动态规划问题的时候都会用到这个例子。

问题描述:

一个旅行者有一个最多能用M公斤的背包,现在有N件物品,

它们的重量分别是W1,W2,...,Wn,

它们的价值分别为P1,P2,...,Pn.

若每种物品只有一件   在不超过M公斤的前提下,求旅行者能获得最大总价值的方案。

输入格式:

M,N

W1,P1

W2,P2

......

问题分析:

经过我们粗略的扫描动态规划的定义,我们了解到动态规划问题基本都是通过建立表格,填表格来解决问题的,这里也不例外。

首先我们需要确定表格内部单元格的逻辑关系。

这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放。

用子问题定义状态:即f[i][j]表示前i件物品恰放入一个容量为j的背包可以获得的最大价值。则其状态转移方程便是:

f[i][j] = max{f[i-1][j], f[i-1][j-w[i]]+P[i]}

为什么这里会出现max呢?因为只能从两个状态而来,也就是取和不取当前物品。 我在前i件物品取得重量不超过j的最大价值,是由取不取第i件物品而得到的。对于【将前i件物品放入容量为v的背包中】这个子问题,若只考虑第i件物品的策略(放或不放),那么就可以转化为一个只牵扯前i-1件物品的问题。如果不放第i件物品,那么问题就转化为“前i-1件物品放入容量为的背包中”,价值为f[i-1][j];如果放第i件物品,那么问题就转化为“前i-1件物品放入剩下的容量为j-w[i]的背包中”,此时能获得的最大价值就是f[i-1][j-w[i]]再加上通过放入第i件物品获得的价值P[i]。

下面我们通过一组真实的数据来过一遍算法流程:

测试数据:
10,3
3,4
4,5
5,6

\

上面这幅图将f[i][j] = max{f[i-1][j], f[i-1][j-w[i]]+P[i]} 这个式子表现得淋漓尽致..动态规划问题基本都是像这样通过建立表格,填表格来解决问题的。

方案代码:

代码如下(为了能够让更多的人可以阅读代码,采用C语言表达):

#include<stdio.h>
int c[10][100];
int knapsack(int m,int n)
{
 int i,j,w[10],p[10];
 for(i=1;i<n+1;i++)
        scanf(" %d,%d",&w[i],&p[i]);
 for(i=0;i<10;i++)
      for(j=0;j<100;j++)
           c[i][j]=0;
 for(i=1;i<n+1;i++)
      for(j=1;j<m+1;j++)
           {
            if(w[i]<=j) 
                     {
                      if(p[i]+c[i-1

补充:综合编程 , 其他综合 ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,