01背包问题算法解释与C代码实现
2014-07-12 11:20
417 查看
题目有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使价值总和最大。基本思路这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放。用子问题定义状态:即f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。则其状态转移方程便是:
这个方程非常重要,基本上所有跟背包相关的问题的方程都是由它衍生出来的。所以有必要将它详细解释一下:“将前i件物品放入容量为v的背包中”这个子问题,若只考虑第i件物品的策略(放或不放),那么就可以转化为一个只牵扯前i-1件物品的问题。如果不放第i件物品,那么问题就转化为“前i-1件物品放入容量为v的背包中”,价值为f[i-1][v];如果放第i件物品,那么问题就转化为“前i-1件物品放入剩下的容量为v-c[i]的背包中”,此时能获得的最大价值就是f[i-1][v-c[i]]再加上通过放入第i件物品获得的价值w[i]。优化空间复杂度以上方法的时间和空间复杂度均为(VN),其中时间复杂度应该已经不能再优化了,但空间复杂度却可以优化到(N)1。这个方程非常重要,基本上所有跟背包相关的问题的方程都是由它衍生出来的。所以有必要将它详细解释一下:“将前i件物品放入容量为v的背包中”这个子问题,若只考虑第i件物品的策略(放或不放),那么就可以转化为一个只牵扯前i-1件物品的问题。如果不放第i件物品,那么问题就转化为“前i-1件物品放入容量为v的背包中”,价值为f[i-1][v];如果放第i件物品,那么问题就转化为“前i-1件物品放入剩下的容量为v-c[i]的背包中”,此时能获得的最大价值就是f[i-1][v-c[i]]再加上通过放入第i件物品获得的价值w[i]。优化空间复杂度以上方法的时间和空间复杂度均为(VN),其中时间复杂度应该已经不能再优化了,但空间复杂度却可以优化到(N)。题目描述:有编号分别为a,b,c,d,e的五件物品,它们的重量分别是2,2,6,5,4,它们的价值分别是6,3,5,4,6,现在给你个承重为10的背包,如何让背包里装入的物品具有最大的价值总和?
只要你能通过找规律手工填写出上面这张表就算理解了01背包的动态规划算法。首先要明确这张表是至底向上,从左到右生成的。为了叙述方便,用e2单元格表示e行2列的单元格,这个单元格的意义是用来表示只有物品e时,有个承重为2的背包,那么这个背包的最大价值是0,因为e物品的重量是4,背包装不了。对于d2单元格,表示只有物品e,d时,承重为2的背包,所能装入的最大价值,仍然是0,因为物品e,d都不是这个背包能装的。同理,c2=0,b2=3,a2=6。对于承重为8的背包,a8=15,是怎么得出的呢?根据01背包的状态转换方程,需要考察两个值,一个是f[i-1,j],对于这个例子来说就是b8的值9,另一个是f[i-1,j-Wi]+Pi;在这里,f[i-1,j]表示我有一个承重为8的背包,当只有物品b,c,d,e四件可选时,这个背包能装入的最大价值f[i-1,j-Wi]表示我有一个承重为6的背包(等于当前背包承重减去物品a的重量),当只有物品b,c,d,e四件可选时,这个背包能装入的最大价值f[i-1,j-Wi]就是指单元格b6,值为9,Pi指的是a物品的价值,即6由于f[i-1,j-Wi]+Pi = 9 + 6 = 15 大于f[i-1,j] = 9,所以物品a应该放入承重为8的背包
![](http://hi.csdn.net/attachment/201110/24/0_1319440763K9kI.gif)
name | weight | value | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
a | 2 | 6 | 0 | 6 | 6 | 9 | 9 | 12 | 12 | 15 | 15 | 15 |
b | 2 | 3 | 0 | 3 | 3 | 6 | 6 | 9 | 9 | 9 | 10 | 11 |
c | 6 | 5 | 0 | 0 | 0 | 6 | 6 | 6 | 6 | 6 | 10 | 11 |
d | 5 | 4 | 0 | 0 | 0 | 6 | 6 | 6 | 6 | 6 | 10 | 10 |
e | 4 | 6 | 0 | 0 | 0 | 6 | 6 | 6 | 6 | 6 | 6 | 6 |
#include <stdio.h>#define N 7#define S 15typedef struct{int s;int n;int job;}KNAPTP;int knap(int s,int n);int w[N+1] = {0,1,4,3,4,5,2,7};void main(){if (knap(S,N))printf("0K!\n" );elseprintf( "N0!\n" );}int knap( int s,int n ){KNAPTP stack[100],x;int top, k, rep;x.s =s; x.n =n;x.job = 0;top = 1; stack[top] = x;k = 0;while ( top>0 && k == 0 ){x = stack[top];rep = 1;while ( !k && rep ){if( x.s==0 ) k = 1; /*已求得一组解*/else if ( x.s<0 || x.n<=0 ) rep = 0;else {x.s = x.s - w[x.n--] ;x.job=1;stack[++top] = x;}}if ( !k ){rep = 1;while ( top >= 1 && rep){x = stack[top--];if ( x.job==1){x.s+=w[x.n + 1];x.job = 2;stack[++top] = x;rep = 0 ;}}}}if (k){/*输出一组解*/while ( top >= 1 ){x = stack[top--];if ( x.job == 1 )printf ("%d\n",w[x.n+1] );}}return k;}
相关文章推荐
- 背包问题---01背包(原理,伪代码,编程实现)
- 精确覆盖问题学习笔记(五)——优化算法的实现代码
- tf–idf算法解释及其python代码实现(下)
- 朴素贝叶斯算法实现分类问题(三类)matlab代码
- c 实现 md5 的算法,只由代码,不做解释.抄的网上的留着备用的.
- 【高级算法】Lasvegas算法解决3SAT问题(C++实现代码)
- python实现的 K-近邻算法代码详细解释
- java代码实现贪心算法删除数字问题
- 分治算法之 棋盘覆盖问题(完整代码实现)
- Dijstra算法的代码实现及解释(最短路径问题)
- 背包问题---01背包(原理,伪代码,编程实现)
- 每天一道算法题(四) (动态规划算法)01背包问题Java实现
- 折半查找实现算法二(递归办法)PS:编译后有一个warning,但不影响结果,代码设计上应该还有些问题
- 【算法】01背包问题的Java实现
- 石子合并;圈型;动态规划;重点在于处理圈型问题;代码内有算法解释;
- Trie树的应用,一道算法问题求解 代码实现
- 约瑟夫环问题的解释及代码实现
- 算法导论第二十五章-所有结点对的最短路径问题-Cpp代码实现
- tf–idf算法解释及其python代码实现(上)
- 程序员代码面试指南:IT名企算法与数据结构题目最优解-字符串问题:C/C++语言实现