动态规划算法

       动态规划方法是对解最优问题的一种方法,一种途径,并不是一种特殊的算法。

       执行步骤:

               1. 找出最优解的性质,刻画结构特征

               2. 递归定义最优解

               3. 自底向上方式计算出最优解

               4. 根据计算最优值时得到的信息,构造一个最优解

        总结为2点,建立最优子结构,保证每一个子结构都是最优解;然后重叠子问题,而不是重复子问题,最优解都是建立在最优子结构的基础之上的。


      下面对动态规划的经典问题进行分析:

【0-1背包问题】

      问题描述:有N件物品和一个容量为V的背包。第i件物品的重量是w[i-1],价值是v[i-1]。求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。

      理解:0-1是指每个物体都有唯一编号,要么放入背包,要么不放。(区别于物品无限背包问题)


      现在指n=5,W=17,物品的价值和重量:

                              


      (1)递归定义最优解的值:

                         

      

          理解:(1)物品的下标是从1开始的,当下标为0时,获得的价值为0;包内放入的物品重量为0,则获得价值也为0.

          (2)第i个物品不能放入包内时,最优解为前一不放该物品最优解c[i-1][w];

          (3)第i个物品能放入时,有两种情况:第i个物品的价值values(i-1)+剩余空间最优解c[i-1][w-Weights[i-1]];不放入第i个物品之前的最优解c[i-1][w]


         (2)算法实现图解

           1> 判断编号为i的物品能否放入到允许重量w中。例如:c[3][7]这个位置,物品3的重量为7,能放入到w=7的包内。

 

              2> 比较将3放入包内(10)+剩余控件最优解(c[2][7-7]=0)与不放入3的最优解(c[2][7]=9)的大小,前者得到的价值大,为最终最优解 ,因此c[3][7]=10

  

 

          (3)c语言代码最优解实现


int ** KnapsackDP(int n,int W,int* Weights,float* Values){                                                         //n:物品个数;W:允许最大数量;Weights:每个物品重量数组;Values:每个物品价值数组
	int i,w;  //i:指定第几个物品;w:允许重量
	int** c=(int**)malloc(sizeof(int*)*(n+1));   //分配空间
	for(n=0;i<=n;i++)      //每一个物品分配W+1种空间存放0--W种不同情况下最优解
		c[j]=(int*)malloc(sizeof(int)*(W+1));
		
	for(w=0;w<W;w++)   //第一行赋值为0(没有物品的情况)
		c[0][w]=0;
	
	for(i=1;i<=n;i++)    //n个物品的循环
		c[i][0]=0;    //第一列赋值为0(包内允许的重量为0)
		for(w=1;w<=W;w++)     //w记录每一种重量的下标
			if(Weights[i-1]<=w){  //i物品能否放入容量为w的包内
				if(Values[i-1]+c[i-1][w-Weights[i-1]]>c[i-1][w])                                                                   //比较将i放入包内+剩余控件最优解与不放入i的最优解的大小
				{
					c[i][w]=Values[i-1]+c[i-1][w-Weights[i-1]];                                                                        //将i放入包内+剩余控件最优解为最优解
				}else{
					c[i][w]=c[i-1][w];  //不放入i的最优解为最优解
				}
			}else{
				c[i][w]=c[i-1][w];   //不放入i的最优解为最优解
			}
		}
		return c;	
}

       该代码实现上表的横向插入,插完第i行然后插入第i+1行。

【总结】

       在问题相对复杂的情况下,代码不能马上理解,这时候我们可以先根据自己的理解对问题的图进行理解,根据自己的理解试试能否理解代码,如果出现差错,可以将例题数据带入代码进行运算,可以理解代码的相对流程,然后再思考代码的整体框架实现。        


     

评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值