您的位置:首页 > 编程语言

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的背包,如何让背包里装入的物品具有最大的价值总和?
nameweightvalue12345678910
a26066991212151515
b23033669991011
c65000666661011
d54000666661010
e460006666666
只要你能通过找规律手工填写出上面这张表就算理解了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的背包
#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;}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: