回溯法实验(0-1背包问题)

合集下载

回溯法解决0-1背包问题

回溯法解决0-1背包问题

回溯法解决0-1背包问题问题描述: 有n件物品和⼀个容量为c的背包。

第i件物品的价值是v[i],重量是w[i]。

求解将哪些物品装⼊背包可使价值总和最⼤。

所谓01背包,表⽰每⼀个物品只有⼀个,要么装⼊,要么不装⼊。

回溯法: 01背包属于找最优解问题,⽤回溯法需要构造解的⼦集树。

在搜索状态空间树时,只要左⼦节点是可⼀个可⾏结点,搜索就进⼊其左⼦树。

对于右⼦树时,先计算上界函数,以判断是否将其减去,剪枝啦啦!上界函数bound():当前价值cw+剩余容量可容纳的最⼤价值<=当前最优价值bestp。

为了更好地计算和运⽤上界函数剪枝,选择先将物品按照其单位重量价值从⼤到⼩排序,此后就按照顺序考虑各个物品。

#include <stdio.h>#include <conio.h>int n;//物品数量double c;//背包容量double v[100];//各个物品的价值double w[100];//各个物品的重量double cw = 0.0;//当前背包重量double cp = 0.0;//当前背包中物品价值double bestp = 0.0;//当前最优价值double perp[100];//单位物品价值排序后int order[100];//物品编号int put[100];//设置是否装⼊//按单位价值排序void knapsack(){int i,j;int temporder = 0;double temp = 0.0;for(i=1;i<=n;i++)perp[i]=v[i]/w[i];for(i=1;i<=n-1;i++){for(j=i+1;j<=n;j++)if(perp[i]<perp[j])//冒泡排序perp[],order[],sortv[],sortw[]{temp = perp[i];perp[i]=perp[i];perp[j]=temp;temporder=order[i];order[i]=order[j];order[j]=temporder;temp = v[i];v[i]=v[j];v[j]=temp;temp=w[i];w[i]=w[j];w[j]=temp;}}}//回溯函数void backtrack(int i){double bound(int i);if(i>n){bestp = cp;return;}if(cw+w[i]<=c){cw+=w[i];cp+=v[i];put[i]=1;backtrack(i+1);cw-=w[i];cp-=v[i];}if(bound(i+1)>bestp)//符合条件搜索右⼦数backtrack(i+1);}//计算上界函数double bound(int i){double leftw= c-cw;double b = cp;while(i<=n&&w[i]<=leftw){leftw-=w[i];b+=v[i];i++;}if(i<=n)b+=v[i]/w[i]*leftw;return b;}int main(){int i;printf("请输⼊物品的数量和容量:");scanf("%d %lf",&n,&c);printf("请输⼊物品的重量和价值:");for(i=1;i<=n;i++){printf("第%d个物品的重量:",i);scanf("%lf",&w[i]);printf("价值是:");scanf("%lf",&v[i]);order[i]=i;}knapsack();backtrack(1);printf("最有价值为:%lf\n",bestp);printf("需要装⼊的物品编号是:");for(i=1;i<=n;i++){if(put[i]==1)printf("%d ",order[i]);}return 0;}时间复杂度分析: 上界函数bound()需要O(n)时间,在最坏的情况下有O(2^n)个右⼦结点需要计算上界,回溯算法backtrack需要的计算时间为O(n2^n)。

算法设计与分析实验报告——基于回溯法的0-1背包等问题

算法设计与分析实验报告——基于回溯法的0-1背包等问题

实验报告. 基于回溯法的0-1背包等问题实验内容本实验要求基于算法设计与分析的一般过程(即待求解问题的描述、算法设计、算法描述、算法正确性证明、算法分析、算法实现与测试),通过回溯法的在实际问题求解实践中,加深理解其基本原理和思想以及求解步骤。

求解的问题为0-1背包。

作为挑战:可以考虑回溯法在如最大团、旅行商、图的m着色等问题中的应用。

实验目的◆理解回溯法的核心思想以及求解过程(确定解的形式及解空间组织,分析出搜索过程中的剪枝函数即约束函数与限界函数);◆掌握对几种解空间树(子集树、排列数、满m叉树)的回溯方法;◆从算法分析与设计的角度,对0-1背包等问题的基于回溯法求解有进一步的理解。

环境要求对于环境没有特别要求。

对于算法实现,可以自由选择C, C++或Java,甚至于其他程序设计语言如Python等。

实验步骤步骤1:理解问题,给出问题的描述。

步骤2:算法设计,包括策略与数据结构的选择。

步骤3:描述算法。

希望采用源代码以外的形式,如伪代码或流程图等;步骤4:算法的正确性证明。

需要这个环节,在理解的基础上对算法的正确性给予证明;步骤5:算法复杂性分析,包括时间复杂性和空间复杂性;步骤6:算法实现与测试。

附上代码或以附件的形式提交,同时贴上算法运行结果截图;步骤7:技术上、分析过程中等各种心得体会与备忘,需要言之有物。

说明:步骤1-6在“实验结果”一节中描述,步骤7在“实验总结”一节中描述。

实验结果步骤1:问题描述。

给定 n个物品,其中第 i 个物品的重量为w i ,价值为 v i 。

有一容积为 W 的背包,要求选择一些物品放入背包,使得物品总体积不超过W的前提下,物品的价值总和最大。

0-1背包问题的限制是,每种物品只有一个,它的状态只有放和不放两种。

0-1背包问题是特殊的整数规划问题,其可用数学语言表述为:对于给定 n >0,W >0,v,w (v i ,w i >0,1≤i ≤n),找出一个 n 元0-1向量x =( x 1, x 2,⋯, x n ) 其中x i ∈{0,1},1≤i ≤n ,使得∑v i n i=1x i 最大,并且∑w i n i=1x i ≤W ,即:max x (∑v i ni=1x i ) s.t.∑w i ni=1x i ≤W, x i ∈{0,1},1≤i ≤n步骤2:算法设计,即算法策略与数据结构的选择。

0-1背包问题——回溯法求解【Python】

0-1背包问题——回溯法求解【Python】

0-1背包问题——回溯法求解【Python】回溯法求解0-1背包问题:问题:背包⼤⼩ w,物品个数 n,每个物品的重量与价值分别对应 w[i] 与 v[i],求放⼊背包中物品的总价值最⼤。

回溯法核⼼:能进则进,进不了则换,换不了则退。

(按照条件深度优先搜索,搜到某⼀步时,发现不是最优或者达不到⽬标,则退⼀步重新选择)注:理论上,回溯法是在⼀棵树上进⾏全局搜索,但是并⾮每种情况都需要全局考虑,毕竟那样效率太低,且通过约束+限界可以减少好多不必要的搜索。

解决本问题思路:使⽤0/1序列表⽰物品的放⼊情况。

将搜索看做⼀棵⼆叉树,⼆叉树的第 i 层代表第 i 个物品,若剩余空间允许物品 i 放⼊背包,扩展左⼦树。

若不可放⼊背包,判断限界条件,若后续继续扩展有可能取得最优价值,则扩展右⼦树(即此 i 物品不放⼊,但是考虑后续的物品)。

在层数达到物品的个数时,停⽌继续扩展,开始回溯。

注:如何回溯呢?怎样得到的,怎样恢复。

放⼊背包中的重量取出,加在bagV上的价值减去。

约束条件:放⼊背包中物品的总质量⼩于等于背包容量限界条件:当前放⼊背包中物品的总价值(i及之前) + i 之后的物品总价值 < 已知的最优值这种情况下就没有必要再进⾏搜索数据结构:⽤⼀个变量记录当前放⼊背包的总价值 bagV(已扩展),⼀个变量记录后续物品的总价值 remainV(未扩展),当前已得到的⼀种最优值 bestV(全局情况),⼀个⽤0/1表⽰的数组bestArr[]记录哪些物品放⼊了背包。

核⼼结构:递归思路进⾏解决。

层层递归,递归到尽头,保留最优值,恢复递归中,层层回溯,即将原来加上去的重量与价值恢复。

# -*- coding:utf-8 -*-def Backtrack(t):global bestV, bagW, bagV,arr, bestArr, cntVif t > n: #某次深度优先搜索完成if bestV < bagV:for i in range(1, n+1):bestArr[i] = arr[i]bestV = bagVelse: #深度优先搜索未完成if bagW + listWV[t][0] <= w: #第t个物品可以放⼊到背包中,扩展左⼦树arr[t] = TruebagW += listWV[t][0]bagV += listWV[t][1]Backtrack(t+1)bagW -= listWV[t][0]bagV -= listWV[t][1]if cntV[t] + bagV > bestV: #有搜索下去的必要arr[t] = FalseBacktrack(t+1)if__name__ == '__main__':w = int(input()) #背包⼤⼩n = int(input()) #物品个数listWV = [[0,0]]listTemp = []sumW = 0sumV = 0for i in range(n):listTemp = list(map(int, input().split())) #借助临时list每次新增物品对应的list加⼊到listWV中sumW += listTemp[0]sumV += listTemp[1]listWV.append(listTemp) #依次输⼊每个物品的重量与价值bestV = 0bagW = 0bagV = 0remainV = sumVarr = [False for i in range(n+1)]bestArr = [False for i in range(n+1)]cntV = [0 for i in range(n+1)] #求得剩余物品的总价值,cnt[i]表⽰i+1~n的总价值 cntV[0] = sumVfor i in range(1, n+1):cntV[i] = cntV[i-1] - listWV[i][1]if sumW <= w:print(sumV)else:Backtrack(1)print(bestV)print(bestArr)print(cntV)检测:1052 65 34 52 43 617[False, True, False, True, False, True][24, 18, 15, 10, 6, 0]。

01背包回溯

01背包回溯

0—1背包问题一、实验目的学习掌握回溯思想。

二、实验内容用回溯求解0—1背包问题,并输出问题的最优解。

0—1背包问题描述如下:给定n种物品和一背包。

物品i的重量是Wi,其价值为Vi,背包的容量是c,问应如何选择装入背包中的物品,使得装入背包中物品的总价值最大。

三、实验条件Jdk1.5以上四、需求分析对于给定n种物品和一背包。

在容量最大值固定的情况下,要求装入的物品价值最大化。

五、回溯法的基本思想:确定了解空间的组织结构后,回溯法就从开始结点(根结点)出发,以深度优先的方式搜索整个解空间。

这个开始结点就成为一个活结点,同时也成为当前的扩展结点。

在当前的扩展结点处,搜索向纵深方向移至一个新结点。

这个新结点就成为一个新的活结点,并成为当前扩展结点。

如果在当前的扩展结点处不能再向纵深方向移动,则当前扩展结点就成为死结点。

换句话说,这个结点不再是一个活结点。

此时,应往回移动(回溯)至最近的一个活结点处,并使这个活结点成为当前的扩展结点。

回溯法即以这种工作方式递归地在解空间中搜索,直至找到所要求的解或解空间中已没有活结点时为止。

六、详细设计/** BackTrace.java** Created on 2007年6月2日, 下午6:09** To change this template, choose Tools | Template Manager* and open the template in the editor.*/package sunfa;import java.util.Date;public class BackTrace {/*** @param args*/public static void main(String[] args) {double w[]={2,2,6,5,4};double v[]={6,3,5,4,6};int n=5;double c=10;knapsack(v,w,c);System.out.println(bestp);}//比较两个元素大小的类private static class Element implements Comparable{int id;double d;private Element(int idd,double dd){id=idd;d=dd;}public int compareTo(Object x){double xd=((Element)x).d;if(d<xd)return -1;if(d==xd)return 0;return 1;}public boolean equals(Object x){return d==((Element)x).d;}}static double c; //背包容量static int n;//物品数static double[]w;//物品重量数组static double[]p; //物品价值数组static double cw;//当前重量static double cp;//当前价值static double bestp; //当前最优值static int [] x;//解static int [] sortX;//排好序之后的解static int [] bestX;//最有解static Date date = null; // @jve:decl-index=0:public static double knapsack(double[]pp,double[]ww,double cc){ c=cc;n=pp.length-1;cw=0.0;cp=0.0;bestp=0.0;Element[]q=new Element[n];//q为单位重量价值数组for(int i=1;i<=n;i++)q[i-1]=new Element(i,pp[i]/ww[i]);MergeSort.mergeSort(q);p=new double[n+1];w=new double[n+1];x=new int[n+1];sortX=new int[n+1];bestX=new int[n+1];for(int i=1;i<=n;i++){p[i]=pp[q[n-i].id];w[i]=ww[q[n-i].id];sortX[i]=q[n-i].id;}backtrack(1);//回溯搜索return bestp;}private static void backtrack(int i){if(i>=n){if(cp>bestp){bestp=cp;for(int j=1;j<=n;j++){bestX[j]=x[j];}}return;}//搜索子树if(cw+w[i]<=c){//进入左子树x[sortX[i]]=1;cw+=w[i];cp+=p[i];backtrack(i+1);cw-=w[i];cp-=p[i];}if(bound(i+1)>bestp)x[sortX[i]]=0;backtrack(i+1);//进入右子树}//计算上界private static double bound(int i){double cleft=c-cw;double bound=cp;//以物品重量价值递减顺序装入物品while(i<=n&&w[i]<=cleft){cleft-=w[i];bound+=p[i];i++;}//装满背包if(i<=n)bound+=p[i]/w[i]*cleft;return bound;}public static String getX(){String solution=String.valueOf(bestX[1]);for(int i=2;i<bestX.length;i++){solution+=",";solution+=String.valueOf(bestX[i]);}return solution;}public static double getBestValue(){return bestp;}}主程序运行结果:。

回溯法实验(0-1背包问题)教学文案

回溯法实验(0-1背包问题)教学文案

回溯法实验(0-1 背包问题)算法分析与设计实验报告第丄次附加实验巔I 軌鬻123^EC70?1O牧品价值分别为:12345678? 10妆品重量和忙值分别为;<2^2> <3,3> <4.4>O^SJ C9,9) <18,10>在实验中并没有生成多组数据,进行比较,也没有利用随机生 成函数,因为在这种有实际有关联的问题中,利用随机生成函数生 成的数据是十分的不合适的,在此我们只需要验证该程序是否正确 即可。

0-1背包问题和之前的最优装载其实质上一样的,都是利用 解空间树,通过深度优先搜索子集树,通过利用上界函数和一些剪 枝策略,从而得到最优解。

由于数据较小,所以时间上并不能反映 出什么东西。

当输入的数据有解时:测试结果实验分析当输入的数据无解时:当输入的数据稍微大点时:四回溯法X FUFO ORe\Debuq\zeno cnejext阀品上数为:M在这一章的回溯算法中,我们用的比较多的就是;利用子集树 来进行问题的探索,就例如上图是典型的一种子集树,在最优装 载、0-1背包都是利用了这种满二叉树的子集树进行求解,然后通 过深度优先的策略,利用约束函数和上界函数,将一些不符合条件 或者不包含最优解的分支减掉,从而提高程序的效率。

对于0-1背包问题我们基本上在每一个算法中都有这么一个实例,足以说明这 个问题是多么经典的一个问题啊,通过几个不同的算法求解这一问 题,我也总算对该问题有了一定的了解。

实验得分附录:完整代码(回溯法)〃0-1背包问题 回溯法求解#i nclude <iostream> using namespacestd;template <class Typew, class Typep> class Knap //Knap 类记录解空间树的结点信息{template <class Typew, class Typep>friend Typep Knapsack(Typep [],Typew [],Typew, int );private :Typep Bound( int i);//计算上界的函数实验心得 助教签名void Backtrack( int i); //回溯求最优解函数Typew c; //背包容量int n; //物品数Typew *w; //物品重量数组|Typep *p; //物品价值数组Typew cw; //当前重量Typep cp; //当前价值Typep bestp; //当前最后价值};template <class Typew, class Typep>Typep Knapsack(Typep p[],Typew w[],Typew c, int n); //声明背包问题求解函数template < class Type>in li ne void Swap (Type &a,Type & b); // 声明交换函数template <class Type>void BubbleSort(Type a[], int n); // 声明冒泡排序函数int main(){int n ; //物品数int c ; //背包容量cout«"物品个数为:";cin»n;cout«"背包容量为:";cin> >c;int *p = new int [n]; //物品价值下标从1开始int *w = new int [n]; //物品重量下标从1开始cout«"物品重量分别为:"<<e ndl;for (int i=1; i<=n; i++){cin> >w[i];}cout«"物品价值分别为:"<<e ndl;for (int i=1; i<=n; i++) //以二元组(重量,价值)的形式输出每物品的信息{cin> >p[i];}coutvv "物品重量和价值分别为:"<<e ndl;for (int i=1; i<=n; i++) //以二元组(重量,价值)的形式输出每个物品的信息{coutvv "(" <<w[i]<< "," <<p[i]<< ")";}coutvve ndl;coutvv "背包能装下的最大价值为:"<<Knapsack(p,w,c,n)<<endl; //输出结果system( "pause");return 0;}template vclass Typew, class Typep>void Knap<Typew,Typep>::Backtrack( int i){if (i>n) //到达叶子节点{bestp = cp; //更新最优值return ;}if (cw + w[i] <= c) // 进入左子树{cw += w[i];cp += p[i];Backtrack(i+1); // 回溯//回溯结束回到当前根结点cw -= w[i];cp -= p[i];}//进入右子树,条件是上界值比当前最优值大,否则就将右子树剪掉if (Bound(i+1)>bestp){Backtrack(i+1);}}template <class Typew, class Typep>Typep KnapvTypew, Typep>::Bound( int i) //计算上界{Typew cleft = c - cw; // 剩余容量Typep b = cp;//以物品单位重量价值递减序装入物品while (i <= n && w[i] <= cleft){cleft -= w[i];b += p[i];i++;}//如果背包剩余容量不足以装下一个物品if (i <= n){b += p[i]/w[i] * cleft; //则将物品的部分装入到背包中}return b;}class Object //定义对象类,作用相当于结构体{template vclass Typew, class Typep>friend Typep Knapsack(Typep[],Typew [],Typew, int ); public : int operator >= (Object a) const // 符号重载函数,重载>=符号{return (d>=a.d);}private :int ID; // 编号float d; //单位重量的价值};template <class Typew, class Typep>Typep Knapsack(Typep p[],Typew w[],Typew c, int n){// 为Knap::Backtrack 初始化Typew W = 0;Typep P = 0;Object *Q = newObject[n]; // 创建Object 类的对象数组| //初始化Object类的对象数组|for (int i=1; i<=n; i++){Q[i-1] .ID = i;Q[i-1].d = 1.0 * p[i]/w[i];P += p[i];W += w[i];}if (W <= c) //装入所有物品{return P;}//依物品单位重量价值降序排序BubbleSort(Q, n);Knap<Typew,Typep> K; // 创建Knap的对象KK.p = n ewTypep[ n+1];K.w = n ewTypew [n+1];for (int i=1; i<=n; i++){K.p[i] = p[Q[i-1]」D];K.w[i] = w[Q[i-1].ID];}//初始化KK.cp = 0;K.cw = 0;K.c = c;K.n = n;K.bestp = 0;//回溯搜索K.Backtrack(1);delete []Q;delete []K.w;delete []K.p;return K.bestp; // 返回最优解} template <class Type>void BubbleSort(Type a[], int n) {//记录一次遍历中是否有元素的交换bool excha nge;for (int i=0; i<n-1;i++){exchange = false ;for (int j=i+1; j<=n-1; j++){if (a[j]>=a[j-1]){Swap(a[j],a[j-1]); exchange = true ;}}//如果这次遍历没有元素的交换,那么排序结束if (exchange==false ){break ;}}} template < class Type>inline void Swap (Type &a,Type &b) // 交换函数{Type temp = a; a = b;b = temp;}。

回溯法(二)——0-1背包问题

回溯法(二)——0-1背包问题

回溯法(⼆)——0-1背包问题 问题1、给定背包容量w,物品数量n,以及每个物品的重量wi,求背包最多能装多少多重的物品。

问题2、给定背包容量w,物品数量n,以及每个物品的重量wi、价值vi,求背包最多能装多少价值的物品。

这是⼀个基本的0-1背包问题,每个物品有两种状态(0:不装、1:装),总共有n步,所以可以⽤回溯法来解决,复杂度是O(2^n)。

C++版代码如下#include <iostream>#include <math.h>#include <cstring>using namespace std;#define MAXSIZE 256int maxWeight = -9999;// 回溯法解决0-1背包问题(其实可以暴⼒(n层for循环),回溯法也是n层for循环,即复杂度是O(2^n))void basePackage(int stuff[], int curState, int state, int curWeight, int weight){// 如果装满了(其实应该是接近装满了)或者已经“⾛完”所有物品if(curState == state || curWeight == weight){if(curWeight > maxWeight)maxWeight = curWeight;return ;}// 不装basePackage(stuff, curState + 1, state, curWeight + 0, weight);// 装if(curWeight + stuff[curState] <= weight)basePackage(stuff, curState + 1, state, curWeight + stuff[curState], weight);}// 回溯法解决0-1背包问题(其实可以暴⼒(n层for循环),回溯法也是n层for循环,即复杂度是O(2^n))// 背包升级问题回溯法解决(加⼊背包的价值)void secPackage(int weight[], int value[], int curV, int curW, int weightLimit, int curS, int n){// 如果背包总重量等于背包限制if(curW == weightLimit || curS == n){if(curV > maxWeight)maxWeight = curV;return ;}// 不装secPackage(weight, value, curV, curW, weightLimit, curS + 1, n);if(curW + weight[curS] <= weightLimit)// 装secPackage(weight, value, curV + value[curS], curW + weight[curS], weightLimit, curS + 1, n);}int main(int argc, char* argv[]){// 总重量,物品个数int w, n;cin>>w>>n;int a[MAXSIZE + 1];for(int i = 0; i < n; i++)cin>>a[i];basePackage(a, 0, n, 0, w);cout<<maxWeight<<endl;return 0;}。

0-1背包问题(回溯法)

0-1背包问题(回溯法)

0-1背包问题(回溯法)实验报告姓名:学号:指导老师:一.算法设计名称:0-1背包问题(回溯法)二.实验内容问题描述:给定n 种物品和一背包。

物品i 的重量是w i ,其价值为v i ,背包的容量为C 。

问应如何选择装入背包的物品,使得装入背包中物品的总价值最大?在选择装入背包的物品时,对每种物品i 只有两种选择,即装入背包或不装入背包。

不能将物品装入背包多次,也不能只装入部分的物品。

三.实验目的1.运用回溯思想,设计解决上述问题的算法,找出最大背包价值的装法。

2.掌握回溯法的应用四.算法设计:问题求解思路1.由0-1背包问题的最优子结构性质,建立计算m[i][j]的递归式如下:i i i w j w j j i m i v w j i m j i m j i m <≤≥⎩⎨⎧-+---=0],1[]}[],1[],,1[max{),(2.查找装入背包物品的回溯函数:从0-1二叉树的根开始搜索:若是叶子节点,则判断此时的价值是否比当前最优的价值大,否则将之替换,并获得最优解向量且返回;若不是叶子节点,则向左右子树搜索,先改变当前的数据状态,递归的调用自己,然后恢复数据状态表示回溯。

3.边界函数bound主要是当还未搜索到叶子节点时,提前判断其子树是否存可能存在更优的解空间,否则进行回溯,即裁剪掉子树的解空间。

关键数据结构及函数模块:(Backtrack.h )#ifndef __BACKTRACK_H__#define __BACKTRACK_H__class BP_01_P{public:∑=ni i i x v 1max ⎪⎩⎪⎨⎧≤≤∈≤∑=n i x C x w i n i i i 1},1,0{1BP_01_P(int w,int n):m_Sum_weitht(0),m_Number(0) {m_Sum_weitht=w;m_Number=n;bestHav=0;bestVal=0;curVal=0;curHav=0;m_hav=new int[n];m_val=new int[n];temop=new int[n];option=new int[n];}~BP_01_P(){delete []m_hav;delete []m_val;delete []temop;delete []option;}void traceBack(int n);int bound(int n);void printBestSoulation();int *m_hav;//每个物品的重量int *m_val;//每个物品的价值int *temop;//01临时解int *option;//01最终解int bestHav;//最优价值时的最大重量int bestVal;//最优的价值int curVal;//当前的价值int curHav;//当前的重量private:int m_Sum_weitht;//背包的总容量int m_Number;//物品的种类};#endif __BACKTRACK_H__五:主要的算法代码实现:(Backtrack.cpp)边界函数:bound( )int BP_01_P::bound(int n){int hav_left=m_Sum_weitht-curHav;int bo=curVal;while(n<m_Number && m_hav[n]<=hav_left){hav_left-=m_hav[n];bo+=m_val[n];n++;}if(n<m_Number){bo+=m_val[n]*hav_left/m_hav[n];//bo+=hav_left;}return bo;}回溯递归函数:traceBack( )void BP_01_P::traceBack(int n){if(n>=m_Number){if(curVal>=bestVal){bestVal=curVal;for(int i=0;i<n;i++){option[i]=temop[i];}return ;}}if(curHav+m_hav[n]<=m_Sum_weitht)//向左子树搜索 {curHav=curHav+m_hav[n];curVal=curVal+m_val[n];temop[n]=1;//标记要选择这个物品traceBack(n+1);curHav=curHav-m_hav[n];curVal=curVal-m_val[n];}if(bound(n+1)>bestVal)//向右子树搜索{temop[n]=0;//标记要丢弃这个物品traceBack(n+1);}}主控函数:(main.cpp)#include <iostream>#include "Backtrack.h"using namespace std;int main(){int number,weigth;cout<<"包的总容量:";cin>>weigth;cout<<"物品的种类:";cin>>number;BP_01_P *ptr=new BP_01_P(weigth,number);cout<<"各种物品的重量:"<<endl;for(int i=0;i<number;i++)cin>>ptr->m_hav[i];cout<<"各种物品的价值:"<<endl;for(i=0;i<number;i++)cin>>ptr->m_val[i];ptr->traceBack(0);ptr->printBestSoulation();cout<<"总重量:"<<ptr->bestHav<<"\t总价值:"<<ptr->bestVal<<endl;return 0;}六:算法分析采用回溯法解决0-1背包问题,明显比动态规划法更优良。

0-1背包问题四种不同算法的实现

0-1背包问题四种不同算法的实现

0-1背包问题四种不同算法的实现兰州交通大学数理与软件工程学院题目0-1背包问题算法实现院系数理院专业班级信计09学生姓名雷雪艳学号200905130指导教师李秦二O一二年 六 月 五 日一、问题描述:1、0—1背包问题:给定n 种物品和一个背包,背包最大容量为M ,物品i 的重量是w i ,其价值是平P i ,问应当如何选择装入背包的物品,似的装入背包的物品的总价值最大?背包问题的数学描述如下:2、要求找到一个n 元向量(x1,x2…xn),在满足约束条件:⎪⎩⎪⎨⎧≤≤≤∑10i i i x M w x 情况下,使得目标函数px ii ∑max ,其中,1≤i ≤n ;M>0;wi>0;pi>0。

满足约束条件的任何向量都是一个可行解,而使得目标函数达到最大的那个可行解则为最优解[1]。

给定n 种物品和1个背包。

物品i 的重量是wi ,其价值为pi ,背包的容量为M 。

问应如何装入背包中的物品,使得装人背包中物品的总价值最大?在选择装人背包的物品时,对每种物品i 只有两种选择,即装入背包、不装入背包。

不能将物品i 装人背包多次,也不能只装入部分的物品i 。

该问题称为0-1背包问题。

0-1背包问题的符号化表示是,给定M>0, w i >0, pi >0,1≤i ≤n ,要求找到一个n 元0-1向量向量(x1,x2…xn), X i =0 或1 , 1≤i ≤n, 使得Mwx ii≤∑ ,而且px ii∑达到最大[2]。

二、解决方案:方案一:贪心算法1、贪心算法的基本原理与分析贪心算法总是作出在当前看来是最好的选择,即贪心算法并不从整体最优解上加以考虑,它所作出的选择只是在某种意义上的局部最优解。

贪心算法不是对所有问题都能得到整体最优解,但对范围相当广的许多问题它能产生整体最优解。

在一些情况下,即使贪心算法不能得到整体最优解,但其最终结果却是最优解的很好近似解。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

算法分析与设计实验报告第五次附加实验
附录:
完整代码(回溯法)
//0-1背包问题回溯法求解
#include<iostream>
using namespace std;
template<class Typew,class Typep>
class Knap //Knap类记录解空间树的结点信息
{
template<class Typew,class Typep>
friend Typep Knapsack(Typep [],Typew [],Typew,int);
private:
Typep Bound(int i); //计算上界的函数
void Backtrack(int i); //回溯求最优解函数
Typew c; //背包容量
int n; //物品数
Typew *w; //物品重量数组¦
Typep *p; //物品价值数组
Typew cw; //当前重量
Typep cp; //当前价值
Typep bestp; //当前最后价值
};
template<class Typew,class Typep>
Typep Knapsack(Typep p[],Typew w[],Typew c,int n); //声明背包问题求解函数template <class Type>
inline void Swap(Type &a,Type &b); //声明交换函数
template<class Type>
void BubbleSort(Type a[],int n); //声明冒泡排序函数
int main()
{
int n ;//物品数
int c ;//背包容量
cout<<"物品个数为:";
cin>>n;
cout<<"背包容量为:";
cin>>c;
int *p = new int[n];//物品价值下标从1开始
int *w = new int[n];//物品重量下标从1开始
cout<<"物品重量分别为:"<<endl;
for(int i=1; i<=n; i++)
{
cin>>w[i];
}
cout<<"物品价值分别为:"<<endl;
for(int i=1; i<=n; i++) //以二元组(重量,价值)的形式输出每物品的信息{
cin>>p[i];
}
cout<<"物品重量和价值分别为:"<<endl;
for(int i=1; i<=n; i++) //以二元组(重量,价值)的形式输出每个物品的信息{
cout<<"("<<w[i]<<","<<p[i]<<") ";
}
cout<<endl;
cout<<"背包能装下的最大价值为:"<<Knapsack(p,w,c,n)<<endl; //输出结果system("pause");
return 0;
}
template<class Typew,class Typep>
void Knap<Typew,Typep>::Backtrack(int i)
{
if(i>n) //到达叶子节点
{
bestp = cp; //更新最优值
return;
}
if(cw + w[i] <= c) //进入左子树
{
cw += w[i];
cp += p[i];
Backtrack(i+1); //回溯
//回溯结束回到当前根结点
cw -= w[i];
cp -= p[i];
}
//进入右子树,条件是上界值比当前最优值大,否则就将右子树剪掉
if(Bound(i+1)>bestp)
{
Backtrack(i+1);
}
}
template<class Typew, class Typep>
Typep Knap<Typew, Typep>::Bound(int i)// 计算上界
{
Typew cleft = c - cw; // 剩余容量
Typep b = cp;
// 以物品单位重量价值递减序装入物品
while (i <= n && w[i] <= cleft)
{
cleft -= w[i];
b += p[i];
i++;
}
// 如果背包剩余容量不足以装下一个物品
if (i <= n)
{
b += p[i]/w[i] * cleft; //则将物品的部分装入到背包中
}
return b;
}
class Object //定义对象类,作用相当于结构体
{
template<class Typew,class Typep>
friend Typep Knapsack(Typep[],Typew [],Typew,int);
public:
int operator >= (Object a)const//符号重载函数,重载>=符号
{
return (d>=a.d);
}
private:
int ID; //编号
float d; //单位重量的价值
};
template<class Typew,class Typep>
Typep Knapsack(Typep p[],Typew w[],Typew c,int n)
{
//为Knap::Backtrack初始化
Typew W = 0;
Typep P = 0;
Object *Q = new Object[n];//创建Object类的对象数组¦
//初始化Object类的对象数组¦
for(int i=1; i<=n; i++)
{
Q[i-1].ID = i;
Q[i-1].d = 1.0 * p[i]/w[i];
P += p[i];
W += w[i];
}
if(W <= c)//装入所有物品
{
return P;
}
//依物品单位重量价值降序排序
BubbleSort(Q,n);
Knap<Typew,Typep> K; //创建Knap的对象K
K.p = new Typep[n+1];
K.w = new Typew[n+1];
for(int i=1; i<=n; i++)
{
K.p[i] = p[Q[i-1].ID];
K.w[i] = w[Q[i-1].ID];
}
//初始化K
K.cp = 0;
K.cw = 0;
K.c = c;
K.n = n;
K.bestp = 0;
//回溯搜索
K.Backtrack(1);
delete []Q;
delete []K.w;
delete []K.p;
return K.bestp; //返回最优解
}
template<class Type>
void BubbleSort(Type a[],int n)
{
//记录一次遍历中是否有元素的交换
bool exchange;
for(int i=0; i<n-1;i++)
{
exchange = false ;
for(int j=i+1; j<=n-1; j++)
{
if(a[j]>=a[j-1])
{
Swap(a[j],a[j-1]);
exchange = true;
}
}
//如果这次遍历没有元素的交换,那么排序结束
if(exchange==false)
{
break ;
}
}
}
template <class Type>
inline void Swap(Type &a,Type &b) //交换函数{
Type temp = a;
a = b;
b = temp;
}。

相关文档
最新文档