蛮力法等求解背包问题报告剖析
算法设计与分析实验报告—01背包问题

算法设计与分析实验报告—0/1背包问题-【问题描述】给定n 种物品和一个背包。
物品i 的重量是iw ,其价值为i v,背包容量为C 。
问应该如何选择装入背包的物品,使得装入背包中物品的总价值最大?【问题分析】0/1背包问题的可形式化描述为:给定C>0, i w >0, i v >0,1i n ≤≤,要求找出n 元0/1向量{}12(,,...,),0,1,1n i x x x x i n ∈≤≤,使得n1i i i w x c =≤∑,而且n1i ii v x=∑达到最大。
因此0/1背包问题是一个特殊的整数规划问题。
0n k w ≤≤1max ni i i v x =∑n1i ii w xc =≤∑{}0,1,1i x i n ∈≤≤【算法设计】设0/1背包问题的最优值为m( i, j ),即背包容量是j ,可选择物品为i,i+1,…,n 时0/1背包问题的最优值。
由0/1背包问题的最优子结构性质,可以建立计算m( i, j )的递归式如下:max{m( i+1, j ), m( i+1, j-i w )+i v } i j w ≥m( i, j )=m(i+1,j)n v n j w >m(n,j)=0 0n k w ≤≤【算法实现】#include <iostream.h> #include<string.h> #include<iomanip.h>int min(int w, int c) {int temp; if (w < c) temp = w;elsetemp = c;return temp;}Int max(int w, int c) {int temp; if (w > c) temp = w;elsetemp = c;return temp;}void knapsack(int v[], int w[], int** m, int c, int n) //求最优值 {int jmax = min(w[n]-1, c);for (int j = 0; j <= jmax; j++)m[n][j] = 0;for (int jj = w[n]; jj <= c; jj++)m[n][jj] = v[n];for(int i = n-1; i > 1; i--)//递归部分{jmax = min(w[i]-1, c);for(int j = 0; j <= jmax; j++)m[i][j] = m[i+1][j];for(int jj = w[i]; jj <= c; jj++)m[i][jj] = max(m[i+1][jj], m[i+1][jj-w[i]]+v[i]);}m[1][c] = m[2][c];if(c >= w[1])m[1][c] = max(m[1][c], m[2][c-w[1]]+v[1]);cout << endl << "最优值:" << m[1][c] << endl;cout<<endl;cout<< "&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&" << endl;}int traceback(int x[], int w[], int** m, int c, int n) //回代,求最优解{out << endl << "得到的一组最优解如下: " << endl;for(int i = 1; i < n; i++){if(m[i][c] == m[i+1][c]) x[i] = 0;else{x[i] = 1;c -= w[i];}}x[n] = (m[n][c]) ? 1:0;for(int y = 1; y <= n; y++)cout << x[y] << "\t";cout << endl;return x[n];}void main(){int n, c;int **m;cout << "&&&&&&&&&&&&&&&&&&&&&欢迎使用0-1背包问题程序&&&&&&&&&&&&&&&&&&&" << endl;cout << "请输入物品个数: ";cin >> n ;cout << endl << "请输入背包的承重:";cin >> c;int *v = new int[n+1];cout << endl << "请输入每个物品的价值 (v[i]): " << endl;for(int i = 1; i <= n; i++)cin >> v[i];int *w = new int[n+1];cout << endl << "请输入每个物品的重量 (w[i]): " << endl;for(int j = 1; j <= n; j++)cin >> w[j];int *x = new int[n+1];m = new int* [n+1]; //动态的分配二维数组for(int p = 0; p < n+1; p++)m[p] = new int[c+1];knapsack (v, w, m, c, n);traceback(x, w, m, c, n);}【运行结果】。
蛮力法、动态规划法、回溯法和分支限界法求解01背包问题【精选】

一、实验内容:分别用蛮力法、动态规划法、回溯法和分支限界法求解0/1背包问题。
注:0/1背包问题:给定种物品和一个容量为的背包,物品的重n C i 量是,其价值为,背包问题是如何使选择装入背包内的物品,使得装i w i v 入背包中的物品的总价值最大。
其中,每种物品只有全部装入背包或不装入背包两种选择。
二、所用算法的基本思想及复杂度分析:1.蛮力法求解0/1背包问题:1)基本思想:对于有n 种可选物品的0/1背包问题,其解空间由长度为n 的0-1向量组成,可用子集数表示。
在搜索解空间树时,深度优先遍历,搜索每一个结点,无论是否可能产生最优解,都遍历至叶子结点,记录每次得到的装入总价值,然后记录遍历过的最大价值。
2)代码:#include<iostream>#include<algorithm>using namespace std;#define N 100//最多可能物体数struct goods //物品结构体{int sign;//物品序号int w;//物品重量int p;//物品价值}a[N];bool m(goods a,goods b){return (a.p/a.w)>(b.p/b.w);}int max(int a,int b){return a<b?b:a;}int n,C,bestP=0,cp=0,cw=0;int X[N],cx[N];/*蛮力法求解0/1背包问题*/int Force(int i){if(i>n-1){if(bestP<cp&&cw+a[i].w<=C){for (int k=0;k<n;k++)X[k]=cx[k];//存储最优路径bestP=cp;}return bestP;}cw=cw+a[i].w;cp=cp+a[i].p;cx[i]=1;//装入背包Force(i+1);cw=cw-a[i].w;cp=cp-a[i].p;cx[i]=0;//不装入背包Force(i+1);return bestP;}int KnapSack1(int n,goods a[],int C,int x[]){Force(0);return bestP;}int main(){goods b[N];printf("物品种数n: ");scanf("%d",&n);//输入物品种数printf("背包容量C: ");scanf("%d",&C);//输入背包容量for (int i=0;i<n;i++)//输入物品i 的重量w 及其价值v {printf("物品%d 的重量w[%d]及其价值v[%d]:",i+1,i+1,i+1);scanf("%d%d",&a[i].w,&a[i].p);b[i]=a[i];}int sum1=KnapSack1(n,a,C,X);//调用蛮力法求0/1背包问题printf("蛮力法求解0/1背包问题:\nX=[ ");for(i=0;i<n;i++)cout<<X[i]<<" ";//输出所求X[n]矩阵printf("]装入总价值%d\n",sum1);bestP=0,cp=0,cw=0;//恢复初始化}3)复杂度分析:蛮力法求解0/1背包问题的时间复杂度为:。
实验项目三 用蛮力法、动态规划法和贪心法求解背包问题

实验项目三 用蛮力法、动态规划法和贪心法求解0/1背包问题实验目的1、学会背包的数据结构的设计,针对不同的问题涉及到的对象的数据结构的设计也不同;2、对0-1背包问题的算法设计策略对比与分析。
实验内容:0/1背包问题是给定n 个重量为{w 1, w 2, … ,wn }、价值为{v 1, v 2, … ,vn }的物品和一个容量为C 的背包,求这些物品中的一个最有价值的子集,并且要能够装到背包中。
在0/1背包问题中,物品i 或者被装入背包,或者不被装入背包,设xi 表示物品i 装入背包的情况,则当xi =0时,表示物品i 没有被装入背包,xi =1时,表示物品i 被装入背包。
根据问题的要求,有如下约束条件和目标函数:于是,问题归结为寻找一个满足约束条件式1,并使目标函数式2达到最大的解向量X =(x 1, x 2, …, xn )。
背包的数据结构的设计:typedef struct object{int n;//物品的编号int w;//物品的重量int v;//物品的价值}wup;wup wp[N];//物品的数组,N 为物品的个数int c;//背包的总重量1、蛮力法蛮力法是一种简单直接的解决问题的方法,常常直接基于问题的描述和所涉及的概念定义。
蛮力法的关键是依次处理所有的元素。
用蛮力法解决0/1背包问题,需要考虑给定n 个物品集合的所有子集,找出所有可能的子集(总重量不超过背包容量的子集),计算每个子集的总价值,然后在他们中找到价值最大的子集。
所以蛮力法解0/1背包问题的关键是如何求n 个物品集合的所有子集,n 个物品的子集有2的n 次方个,用一个2的n 次方行n 列的数组保存生成的子集,以下是生成子集的算法:⎪⎩⎪⎨⎧≤≤∈≤∑=)1(}1,0{1n i x C x w i n i i i (式1)∑=ni i i x v 1max (式2)void force(int a[16][4])//蛮力法产生4个物品的子集{int i,j;int n=16;int m,t;for(i=0;i<16;i++){ t=i;for(j=3;j>=0;j--){m=t%2;a[i][j]=m;t=t/2;}}for(i=0;i<16;i++)//输出保存子集的二维数组{for(j=0;j<4;j++){printf("%d ",a[i][j]);}printf("\n");}}以下要依次判断每个子集的可行性,找出可行解:void panduan(int a[][4],int cw[])////判断每个子集的可行性,如果可行则计算其价值存入数组cw,不可行则存入0{int i,j;int n=16;int sw,sv;for(i=0;i<16;i++){sw=0;sv=0;for(j=0;j<4;j++){sw=sw+wp[j].w*a[i][j];sv=sv+wp[j].v*a[i][j];}if(sw<=c)cw[i]=sv;elsecw[i]=0;}在可行解中找出最优解,即找出可行解中满足目标函数的最优解。
01背包问题实验报告

算法设计与分析实验报告书实验名称:0/1背包问题学号:姓名:实验时间:2015年 6 月 1 日一实验目的和要求(1)深刻掌握贪心法、动态规划法、回溯法的设计思想并能熟练运用(2)理解这样一个观点:同样的问题可以用不同的方法来解决,一个好的算法是反复努力和重新修正的结果。
二实验内容(1)分别用蛮力法贪心法、动态规划法、回溯法设计0/1背包问题的算法。
(2)分析算法随n和C变化的时间性能,随机产生参数n和C,收集算法执行的时间(3)讨论n和C变化时,动态规划法和回溯法的时间性能。
(4)讨论几种算法在该问题求解上的特点。
三实验环境VC++6.0四设计思想及实验步骤蛮力法的设计思想和步骤将所有排列下的背包的重量和价值都计算出来,选择重量不大于背包的总重量下的最大价值。
贪心法的设计思想和步骤首先计算每种物品单位重量的价值vi/wi;按单位价值对物品进行升序排列。
然后,依贪心选择策略,将尽可能多的单位重量价值最高的物品装入背包,直到背包装满为止。
动态规划法的设计思想和步骤令V(i, j)表示在前i个物品中能够装入容量为j的背包中的物品的最大价值,则可以得到如下动态函数:V(i, j)=0 (i=0或j=0)V( i, j) = V(i-1, j) j<w[i]V( i, j) = max{V(i-1, j), V(I, j-1)+v[i]} j>=w[j]按照下述方法来划分段:第一段只装入前1个物品,确定在各种情况下的背包能够得到的最大价值;第二阶段,只装入2个物品,确定在各种情况下的背包能够得到的最大价值;以此类推,直到第n个阶段。
最后V(n, C)便是容量为C的背包中装入n个物品时获取到的最大价值。
回溯法的设计思想和步骤为了避免生成那些不可能产生最佳解的问题状态,要不断的利用越约束条件来剪掉那些实际上不可能产生所需解的节点,以减少问题额计算量。
对于n种可选物品的0/1背包问题,其解空间长度由长度为n的0-1向量组成,可用子集数表示。
动态规划方案解决算法背包问题实验报告含源代码

动态规划方案解决算法背包问题实验报告含嘿,大家好!今天我来给大家分享一个相当有趣的编程问题——背包问题。
这可是算法领域里的经典难题,也是体现动态规划思想的好例子。
我会用我10年的方案写作经验,给大家带来一份详细的实验报告,附带哦!让我简单介绍一下背包问题。
假设你是一个盗贼,要盗取一个博物馆里的宝贝。
博物馆里有n个宝贝,每个宝贝都有它的价值v和重量w。
你有一个承重为W的背包,你希望放入背包的宝贝总价值最大,但总重量不能超过背包的承重。
这个问题,就是我们要解决的背包问题。
一、算法思路1.创建一个二维数组dp,dp[i][j]表示前i个宝贝放入一个承重为j的背包中,能达到的最大价值。
2.初始化dp数组,dp[0][j]=0,因为如果没有宝贝,那么无论背包承重多少,价值都是0。
3.遍历每个宝贝,对于每个宝贝,我们有两种选择:放入背包或者不放入背包。
4.如果不放入背包,那么dp[i][j]=dp[i-1][j],即前i-1个宝贝放入一个承重为j的背包中,能达到的最大价值。
5.如果放入背包,那么dp[i][j]=dp[i-1][j-w[i]]+v[i],即前i-1个宝贝放入一个承重为j-w[i]的背包中,加上当前宝贝的价值。
6.dp[i][j]取两种情况的最大值。
二、defknapsack(W,weights,values,n):dp=[[0for_inrange(W+1)]for_inrange(n+1)]foriinrange(1,n+1):forjinrange(1,W+1):ifj>=weights[i-1]:dp[i][j]=max(dp[i-1][j],dp[i-1][j-weights[i-1]]+values[i -1])else:dp[i][j]=dp[i-1][j]returndp[n][W]测试数据W=10weights=[2,3,4,5]values=[3,4,5,6]n=len(values)输出结果max_value=knapsack(W,weights,values,n)print("最大价值为:",max_value)三、实验结果分析通过上面的代码,我们可以得到最大价值为15。
实验项目1:蛮力法与分治法应用

实验项目1:蛮力法与分治法应用1、目的与要求:实验目的:了解蛮力法和分治法的基本思想,学会运用蛮力法和分治法解决实际系统设计应用中碰到的问题。
实验要求:用蛮力法实现选择、冒泡排序,或旅行商问题、背包问题等问题(任选其中之一)。
用分治法实现合并排序或快速排序。
要求写出算法的伪代码描述,并编写程序实现之,相关算法放在函数内实现,主程序给出测试用例,要设计足够多的相关测试用例,验证程序的正确性。
注意观察程序执行结果和运行的时间。
实验报告要求给出问题定义及算法的伪代码描述,程序设计的代码,算法的测试用例及结果,并分析算法的时间效率,回答指导书中的思考题。
2、实验内容:(2)用分治法实现快速排序、合并排序算法。
本实验主要是用分治法实现合并排序,快速排序程序等。
合并排序算法描述:MergeSort ( A[0...p-1] )// input 待排序数组A[0..n-1]// output 非降序排列的数组A[0..n-1]if ( n>1 ) {//至少有2个元素Copy A[0.. n/2-1 ] to B[0.. n/2-1 ];Copy A[n/2..n-1 ] to C[0.. n/2-1 ];MergeSort ( B[0.. n/2-1 ] );MergeSort (C[0.. n/2-1 ]t);Merge (B, C, A); //复制回数组a快速排序算法描述:QuickSort ( A[1.. r ] ){if (l<r) s=Partition( A[l,r] ); // s 是分裂位置QuickSort ( A[l..s-1] ); //对左半段排序QuickSort ( A[s+1,r); //对右半段排序}Partition ( A[l..r] ){p=A[[l] ;i = l; j = r + 1;repeatedrepeated i=i+1; until A[i]> p // 将>= x的元素交换到左边区域repeated i=i+1; until A[i]> p // <= x的元素交换到右边区域Swap( A[i], A[j] )Until i>jSwap( A[i] = a[j] );Swap( A[l], A[j] )return j;要求先给出算法的伪代码,然后用C++或其他程序设计语言编写程序实现之,并设计相关的测试用例,验证程序的正确性。
算法设计-01背包问题的分析

算法设计与分析------0/1背包问题实例研究班级:090402学号:20091236姓名:王龙一、问题描述有N件物品和一个容量为V的背包。
第i件物品的费用是c[i],价值是w[i]。
求解将哪些物品装入背包可使价值总和最大。
二、基本思路这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放。
用子问题定义状态:即f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。
则其状态转移方程便是:f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}这个方程非常重要,基本上所有跟背包相关的问题的方程都是由它衍生出来的。
所以有必要将它详细解释一下:“将前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]。
三、优化空间复杂度我们可以很容易的得出,以上方法的时间和空间复杂度均为O(VN),其中时间复杂度应该已经不能再优化了,但空间复杂度却可以优化到O。
先考虑上面说的基本思路如何实现,肯定是有一个主循环i=1..N,每次算出来二维数组f[i][0..V]的所有值。
那么,如果只用一个数组f[0..V],能不能保证第i次循环结束后f[v]中表示的就是我们定义的状态f[i][v]呢?f[i][v]是由f[i-1][v]和f[i-1][v-c[i]]两个子问题递推而来,能否保证在推f[i][v]时(也即在第i 次主循环中推f[v]时)能够得到f[i-1][v]和f[i-1][v-c[i]]的值呢?事实上,这要求在每次主循环中我们以v=V..0的顺序推f[v],这样才能保证推f[v]时f[v-c[i]]保存的是状态f[i-1][v-c[i]]的值。
背包问题总结

背包问题总结背包问题总结01背包问题01背包问题解决⼀个这样的问题,即在付出的代价有限,选取的物品也有限的条件(拿与不拿)下如何达到最优解的问题。
⾯临的棘⼿情况是,并不是代价可以承受的情况下总是选择拿取物品,所获得的价值会达到最⼤,可能出现由于⾸先拿取⼀个低价值的物品导致⽆法后续⾼价值的物品⽆法拿取错失最优价值的情况。
解决办法:如果我们遍历所有可能,通过⽐较那么我们⼀定可以得到最优解,但是代价过于⾼昂,存在许多⼦问题的冗余计算的过程,若要解决⼦问题的冗余,能否将⼦问题的状态保存,之后再在需要时找出,这样就能避免⼤量的计算。
动态规划将⼤问题分解为⼀个个⼦问题,⽗问题的最优解有赖于⼦问题最优解的来实现,譬如:如果我们拥有 i- 1种物品在0n**种代价限n情况的最优解呢?制的情况下的最优解,我们能否找出**i**种物品**0在是否选择第i件物品的当⼝,我们有两种选择:不选择:直接继承i-1在代价限制条件下的最优解选择:那么在付出代价之后我们可以将付出代价后的最优解与i物品的价值组合获得最优解⽬标是获得选择/不选择情况下的最优解,所以可以选择其中的最⼤值代码实现:if(j<space[i])dp[i][j]=dp[i-1][j];elsedp[i][j]=max(dp[i-1][j],dp[i-1][j-space[i]]+val[i]);空间优化:如⽤⼀个⼀维数组记录,通过逆序遍历,通过⽐较dp[i]与dp[i - w] + v(倒序情况下dp[i-w]没有被更新)既可以获得最优解代码实现:for(i=1;i<=N;i++)//遍历n种物品选择情况{for(j=C;j>=space[i];j--)//倒序同时保证代价能够承受{dp[j]=max(dp[j],dp[j-space[i]]+val[i]);}}实际问题分析这是⼀个典型的01背包问题,在背包体积有限为V的情况下有N件物品进⾏选择,每件物品都有相应的价值与代价⼀个有趣的问题这个问题需要解决如何将物品分割,使得物品分隔相对均匀且A堆不⼩于B堆这同样是01背包问题,01背包问题可解决的是背包空间有限的情况下,所能获取到的最⼤资源的问题。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
算法综合实验报告学号:姓名:一、实验内容:分别用蛮力、动态规划、贪心及分支限界法实现对TSP问题或者0-1背包问题的求解,并至少用两个测试用例对所完成的代码进行正确性及效率关系上的验证。
二、程序设计的基本思想、原理和算法描述:1、蛮力法(1)数据结构:使用一维数组存储物品的价值和重量还有下标。
(2)函数组成除主函数外还有一个subset()函数,在此函数中列出所有的子集列出子集的同时求解最大价值,并且物品总重量要小于背包总容量。
(3)输入/输出设计首先通过键盘输入物品的总重量,再输入背包总容量,依次输入每个物品的重量,对应输入相应重量的价值,循环直至输入所有物品的重量和价值。
最后输出物品的最大价值。
本程序通过键盘进行输入、屏幕进行输出。
(根据实际程序情况,还可以选择随机产生输入数据、将输出数据输出到文件等其它方式)(4)符号名说明w[1001]为物品重量的集合,v[1001]为物品价值的集合,n为物品数量,m为背包总容量,x[1001]用来存储物品是否装入背包,0为不装入,1为装入。
用a[1001]来存储下标,用下标找出所有子集。
(5)算法描述采用增量构造的方法来构造出物品的所有子集,对物品的下标应用此方法进行构造,下标与物品相对应,选出子集时物品的重量加之前重量小于背包总重量时将价值加上去,最后选出能装入背包的物品的最大值。
2、 动态规划法(1)数据结构:使用一维数组存储各个物品价值,重量,使用一个二维数组存储动态规划的整体求解的表,并以背包容量为最大列号,物品个数为最大行号。
(2)函数组成:除主函数外由两个函数组成,一个是求解两个数中的大的一个的函数,另一个则是进行动态规划求解的函数,在使用动态规划方法具体求解时调用求最大值函数,在主程序之中调用动态规划函数。
(3)输入/输出设计:首先通过键盘输入物品的总重量,再输入背包总容量,依次输入每个物品的重量,对应输入相应重量的价值,循环直至输入所有物品的重量和价值。
输出物品的最大价值。
本程序通过键盘进行输入、屏幕进行输出。
(根据实际程序情况,还可以选择随机产生输入数据、将输出数据输出到文件等其它方式)(4)符号名说明:w[1001]为物品重量的集合,v[1001]为物品价值的集合,n 为物品数量,m 为背包总容量,x[1001]用来存储物品是否装入背包,0为不装入,1为装入。
V[1001][1001]用来存储动态规划具体求解过程,V[n][m]为最终结果最大价值。
(5)算法描述:[1].背包容量不足以装入物品i ,则装入前i 个物品得到的最大价值和装入前i-1个物品得到的最大价值是相同的,则x[i]=0,背包不增加价值。
[2].背包容量可以装入物品i ,如果把第i 个物品装入背包,则背包中物品的价值等于前i-1个物品装入容量为j-w[i]的背包中的价值加上第i 个物品的价值;如果第i 个物品没有装入背包,则背包中物品的价值等于把前i-1个物品装入容量为j 的背包中所取得的价值。
取二者中价值较大者作为把前i 个物品装入容量为j 的背包中的最优解。
),(j i V 表示在前)1(n i i ≤≤个物品中能够装入容量为)1(C j j ≤≤的背包中的物品的最大值,则可以得到如下动态函数:0),0()0,(==j V i V{}⎩⎨⎧≥+---<-=)(),1(),,1(max ))(,1(),(i i i i w j v w j i V j i V w j j i V j i V3、 贪心法(1) 数据结构:定义多个一维数组存储数据进行贪心选择。
(2)函数组成 : 编写了一个选择排序函数,一个判断是否能装入包中的函数,一个主函数,在主函数中调用判断函数,在判断函数初始调用排序函数将单位价值重量从大到小进行排序。
(3)输入/输出设计:首先通过键盘输入物品的总重量,再输入背包总容量,依次输入每个物品的重量,对应输入相应重量的价值,循环直至输入所有物品的重量和价值。
先输出放入背包中的物品序号,在输出总价值,最后输出背包总容量。
本程序通过键盘进行输入、屏幕进行输出。
(根据实际程序情况,还可以选择随机产生输入数据、将输出数据输出到文件等其它方式)(4)符号名说明:w[1001]为物品重量的集合,v[1001]为物品价值的集合,a[1001]为单位物品价值集合,n 为物品数量,m 为背包总容量,x[1001]用来存储物品是否装入背包,0为不装入,1为装入。
(5)算法描述:制定贪心策略,求出单位物品价值并从大到小进行排序,依照排序结果从大到小放入,知道物品重量大于背包剩余容量为止,但是求出的并不是最优解,贪心法无法求出0/1背包的最优解,只能求出背包问题的最优解。
4、 分支限界法(1) 数据结构定义一个优先队列存储分支限界所使用的树的节点,使用一维数组存储物品的重量和价值。
(2)函数组成一个构造函数,申请动态数组构造树,一个析构函数,删掉动态申请的数组,一个计算上界的函数,一个生成新节点的函数,一个将节点加入优先队列的函数,一个取上界最大节点的函数,一个背包问题求解的函数,一个显示函数,在主函数中调用函数求解。
本程序还使用了类和结构体。
(3)输入/输出设计通过键盘先输入背包总容量,再输入物品总数,依次输入每个物品的重量,依次输入每个物品的价值。
输出最大价值以及每个物品是否装入背包中本程序通过键盘进行输入、屏幕进行输出。
(根据实际程序情况,还可以选择随机产生输入数据、将输出数据输出到文件等其它方式)(4)符号名说明Cw为当前背包装载量,cv为当前背包价值,ub节点的上界值,c为背包的容量,n为物品数量,x[]记录物品是否放入背包,0为不放入,1为放入,w[]为存放物品重量的数组,v[]为存放物品价值的数组。
(5)算法描述给定n 种物品和一个容量为C 的背包, 物品i 的重量是Wi, 其价值为Vi , 0/ 1 背包问题是如何选择装入背包的物品(物品不可分割) , 使得装入背包中物品的总价值最大,一般情况下, 解空间树中第i 层的每个结点, 都代表了对物品1~ i 做出的某种特定选择, 这个特定选择由从根结点到该结点的路径唯一确定: 左分支表示装入物品, 右分支表示不装入物品。
对于第i 层的某个结点, 假设背包中已装入物品的重量是w, 获得的价值是v, 计算该结点的目标函数上界的一个简单方法是把已经装入背包中的物品取得的价值v, 加上背包剩余容量W - w 与剩下物品的最大单位重量价值vi + 1/ wi + 1的积,于是,得到限界函数:u b = v + ( W - w) × ( vi + 1/ wi + 1 ) 根据限界函数确定目标函数的界[ down , up],然后, 按照广度优先策略遍历问题的空间树。
三、源程序及注释:1、蛮力法#include<cstdio>#include<iostream>using namespace std;int x[1001]={0};int w[1001],v[1001];int maxValue=0;int subset(int n,int m,int* A,int cur)//n是数组长度,A为待求子集数组,cur用于递归记录{int weight=0;int value=0;for(int i=0; i<cur; i++) //这个用于输出子集{//printf("%d ",A[i]);if(weight+w[A[i]]<m){x[A[i]]=1;weight=weight+w[A[i]];value=value+v[A[i]];}}if(maxValue<value)maxValue=value;//printf("\n");int s = cur? A[cur-1]+1 : 0; //判断cur是否是0,避免越界,是0的话就取s=0,非零的话s=A[cur-1]for( i=s; i<n; i++) //递归构造子集{A[cur] = i;subset(n,m,A,cur+1);}return maxValue;}int main(){int n,m;int a[1000];cout<<"请输入物品总数量:"<<endl;cin>>n;//输入物品总数量cout<<"请输入背包总容量:"<<endl;cin>>m;//输入背包总容量cout<<"请依次输入物品的重量和价值"<<endl;for(int i=0;i<n;i++){cin>>w[i];cin>>v[i];a[i]=i; //记录下标cout<<"总价值为:"<<subset(n,m,a,0)<<endl;return 0;}2、动态规划法#include<iostream>#include<cmath>using namespace std;int V[1002][1002];int w[1001],v[1001];int max(int xx,int yy) //判断两个数谁大,返回大的那个值{if(xx>=yy)return xx;elsereturn yy;}int KnapSack(int *w,int *v,int n,int m){int x[1001]={0};int i,j;for(i=0;i<=n;i++) //初始化第0列为0V[i][0]=0;for(j=0;j<=m;j++) //初始化第0行为0V[0][j]=0;for(i=1;i<=n;i++) //在背包能放下的情况下,如果放入后比i-1个物品装入后价值还小则不放入for(j=1;j<=m;j++) //计算第i行,进行第i次迭代{if(j<w[i])V[i][j]=V[i-1][j];elseV[i][j]=max(V[i-1][j],(V[i-1][j-w[i]]+v[i]));}for(j=m,i=n;i>0;i--) //求装入背包的物品{if(V[i][j]>V[i-1][j]){x[i]=1;j=j-w[i];}elsex[i]=0;return V[n][m]; //返回背包取得的最大价值}int main(){int n,m;//n为物品数量,m为背包容量int i;int maxValue;cout<<"请输入物品数量"<<endl;cin>>n;cout<<"请输入背包容量"<<endl;cin>>m;cout<<"请依次输入每个物品的重量和价值(注:重量在前,价值在后)"<<endl;for(i=1;i<=n;i++){cin>>w[i];cin>>v[i];}maxValue=KnapSack(w,v,n,m);cout<<"最大价值是:"<<maxValue<<endl;return 0;}3、贪心法:#include<iostream>#include<iomanip>using namespace std;int n,m;int w[1001],v[1001];double a[1001];int maxValue=0;int b[1001];//存储物品序号int x[1001]={0}; //0为不放入背包,1为放入背包void Sort(int n,double *a,int *w,int *v,int *b)//排序函数{for(int e=0;e<n;e++) //将单位重量价值从大到小排序for(int t=n-1;t>e;t--){if(a[e]<a[t]){int temp=a[e];int q=w[e];int s=v[e];int p=b[e];a[e]=a[t];a[t]=temp;w[e]=w[t];w[t]=q;v[e]=v[t];v[t]=s;b[e]=b[t];b[t]=p;}}}int KnapSack(int n,int m,int *w,int *v,int *x)// 判断是否能装入背包{Sort(n,a,w,v,b);for(int j=0;w[j]<m;j++){x[j]=1;maxValue=maxValue+v[j];m=m-w[j];}return maxValue;}int main(){cin>>n; //输入物品总个数cin>>m; //输入背包总容量int weight=0;for(int i=0;i<n;i++){cin>>w[i]; //输入物品重量cin>>v[i]; //输入物品价值a[i]=v[i]/w[i]; //求得单位重量价值b[i]=i+1; //记录物品序号}maxValue=KnapSack(n,m,w,v,x);for(int j=0;j<n;j++){if(x[j]==1){cout<<"第"<<b[j]<<"个物品装入"<<" ";weight=weight+w[j];}}cout<<endl;cout<<maxValue<<endl; //输出能装入的总价值cout<<"总重量为:"<<weight<<endl;return 0;}5、分支限界法#include<iostream>#include<cstdio>using namespace std;int *x;struct node{ //结点表结点数据结构node *parent, //父结点指针*next; //后继结点指针int level, //结点的层bag, //节点的解cw, //当前背包装载量cv; //当前背包价值float ub; //结点的上界值};class Knap{private:struct node *front, //队列队首*bestp,*first; //解结点、根结点int *v,*w,n,c,*M;//背包价值、重量、物品数、背包容量、记录大小顺序关系long lbestp;//背包容量最优解public:void Sort();Knap(int *pp,int *ww,int cc,int nn);~Knap();float Bound(int i,int cw,int cv); //计算上界node *nnoder(node *pa,int ba,float uub);//生成一个结点 ba=1生成左节点 ba=0生成右节点void addnode(node *nod); //将结点添加到队列中void deletenode(node *nod); //将结点队列中删除struct node *nextnode(); //取下一个节点void display(); //输出结果void solvebag(); //背包问题求解};Knap::Knap(int *pp,int *ww,int cc,int nn) //构造函数{int i;n=nn;c=cc;v=new int[n]; //动态申请数组w=new int[n];M=new int[n];for(i=0;i<n;i++){v[i]=pp[i];w[i]=ww[i];M[i]=i;}front=new node[1];front->next=NULL;lbestp=0;bestp=new node[1];bestp=NULL;Sort();}Knap::~Knap() //析构函数{delete []first;delete []front;delete []bestp;delete []v;delete []w;}float Knap::Bound(int i,int cw,int cv){ // 计算上界int left=c-cw;float b=(float)cv;while (i<n&&w[i]<=left){left-=w[i];b+=v[i];i++;}if (i<n) b+=1.0*v[i]/w[i]*left;return b;}node * Knap::nnoder(struct node *pa,int ba,float uub){ //生成一个新结点node * nodell=new(node);nodell->parent=pa;nodell->next=NULL;nodell->level=(pa->level)+1;nodell->bag=ba;nodell->ub=uub;if(ba==1){nodell->cw=pa->cw+w[pa->level];nodell->cv=pa->cv+v[pa->level] ;}else{nodell->cw=pa->cw;nodell->cv=pa->cv;}return(nodell);}void Knap::addnode(node *no){ //将结点加入优先队列node *p=front->next,*next1=front;float ub=no->ub;while(p!=NULL){if(p->ub<ub){no->next=p;next1->next=no;break;}next1=p;p=p->next;}if(p==NULL){next1->next=no;}}node *Knap::nextnode(){ //取上限最大结点node *p=front->next;front->next=p->next;return(p);}void Knap::Sort(){int i,j,k,kkl;float minl;for(i=1;i<n;i++){minl=1.0*v[i]/w[i];k=0;for(j=1;j<=n-i;j++){if(minl<1.0*v[j]/w[j]){minl=1.0*v[j]/w[j];swap(v[k],v[j]);swap(w[k],w[j]);swap(M[k],M[j]);k=j;}}}}void Knap::display() //显示函数{int i;cout<<"最大价值是:"<<lbestp<<endl;for(i=n;i>=1;i--){x[M[i-1]]=bestp->bag;bestp=bestp->parent;}cout<<"物品状态为(0为不装入,1为装入):"<<endl;for(i=1;i<=n;i++)cout<<"x("<<i<<")="<<x[i-1]<<endl;}void Knap::solvebag(){ //背包问题求解int i;float ubb;node *aa;first=new node[1]; //根结点first->parent=NULL;first->next=NULL;first->level=0;first->cw=0;first->cv=0;first->bag=0;ubb=Bound(0,0,0);first->ub=ubb;front->next=first;while(front->next!=NULL){aa=nextnode();i=aa->level;if(i==n-1){if(aa->cw+w[i]<=c&&(long)(aa->cv+v[i])>lbestp){lbestp=aa->cv+v[i];bestp=nnoder(aa,1,(float)lbestp);}if((long)(aa->cv)>lbestp){lbestp=aa->cv;bestp=nnoder(aa,0,(float)lbestp);}}if(i<n-1){if(aa->cw+w[i]<=c&&Bound(i+1,aa->cw+w[i],aa->cv+v[i])>(float)lbestp){ubb=Bound(i,aa->cw+w[i],aa->cv+v[i]);addnode(nnoder(aa,1,ubb));}ubb=ubb=Bound(i,aa->cw,aa->cv);if(ubb>lbestp)addnode(nnoder(aa,0,ubb));}}display();}void main(){int c,n;int i=0;int *v;int *w;cout<<"请输入背包容量:"<<endl;cin>>c;cout<<"请输入物品数:"<<endl;cin>>n;x=new int[n];v=new int[n];w=new int[n];cout<<"请输入"<<n<<"个物品的重量:"<<endl;for(i=0;i<n;i++)cin>>w[i];cout<<"请输入"<<n<<"个物品价值:"<<endl;for(i=0;i<n;i++)cin>>v[i];x=new int[n];Knap knbag(v,w,c,n);knbag.solvebag();return;}四、运行输出结果:1、蛮力法测试1:测试2:2、动态规划法测试1:测试2:3、贪心法:测试1:测试2:4、分支限界法测试1:测试2:五、调试和运行程序过程中产生的问题及采取的措施:1、在传数组时一开始就是在报错,最后我使用了全局变量定义数组,使用了指针直接传指针,eg:max(a,b),a,b,是数组,定义函数时void Sort(int n,double *a,int *w,int *v,int *b)才可以进行。