用回溯法和队列式分支限界算法求解0-1背包问题

合集下载

回溯法和分支限界法解决背包题

回溯法和分支限界法解决背包题

0-1背包问题计科1班朱润华 32方法1:回溯法一、回溯法描述:用回溯法解问题时,应明确定义问题的解空间。

问题的解空间至少包含问题的一个(最优)解。

对于0-1背包问题,解空间由长度为n的0-1向量组成。

该解空间包含对变量的所有0-1赋值。

例如n=3时,解空间为:{(0,0,0),(0,1,0),(0,0,1),(1,0,0),(0,1,1),(1,0,1),(1,1,0),(1,1,1)}然后可将解空间组织成树或图的形式,0-1背包则可用完全二叉树表示其解空间给定n种物品和一背包。

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

问:应如何选择装入背包的物品,使得装入背包中物品的总价值最大形式化描述:给定c >0, wi >0, vi >0 , 1≤i≤n.要求找一n元向量(x1,x2,…,xn,), xi∈{0,1}, ∑ wi xi≤c,且∑ vi xi达最大.即一个特殊的整数规划问题。

二、回溯法步骤思想描述:0-1背包问题是子集选取问题。

0-1 背包问题的解空间可以用子集树表示。

在搜索解空间树时,只要其左儿子节点是一个可行节点,搜索就进入左子树。

当右子树中有可能含有最优解时,才进入右子树搜索。

否则,将右子树剪去。

设r是当前剩余物品价值总和,cp是当前价值;bestp是当前最优价值。

当cp+r<=bestp时,可剪去右子树。

计算右子树上界的更好的方法是将剩余物品依次按其单位价值排序,然后依次装入物品,直至装不下时,再装入物品一部分而装满背包。

例如:对于0-1背包问题的一个实例,n=4,c=7,p=[9,10,7,4],w=[3,5,2,1]。

这4个物品的单位重量价值分别为[3,2,3,5,4]。

以物品单位重量价值的递减序装入物品。

先装入物品4,然后装入物品3和1.装入这3个物品后,剩余的背包容量为1,只能装的物品2。

由此得一个解为[1,,1,1],其相应价值为22。

尽管这不是一个可行解,但可以证明其价值是最优值的上界。

分支限界法结局0~1背包问题

分支限界法结局0~1背包问题

Bound( i ) cleft = c – cw; 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; }

此后,从活结点表中取下一结点成为当前扩展结点,并重复上述结 点扩展过程。这个过程一直持续到找到所需的解或活结点表为空时为 止。
与回溯法区别
求解目标不同: 一般而言,回溯法的求解目标是找出解空间树中满 足的约束条件的所有解,而分支限界法的求解目标 则是尽快的找出满足约束条件的一个解。

搜索方法不同 回溯法使用深度优先方法搜索,而分支限界一般用宽 度优先或最佳优先方法来搜索;

按照队列先进先出(FIFO)原则选取下一个节点为扩展节点;
数据结构:队列
(2)优先队列式分支限界法

按照优先队列中规定的优先级选取优先级最高的节点成为当前 扩展节点。 数据结构:堆 最大优先队列:使用最大堆,体现最大效益优先

最小优先队列:使用最小堆,体现最小费用优先
【0-1背包问题】
物品数量n=3,重量w=(20,15,15),价值v=(40,25,25) 背包容量c=30,试装入价值和最大的物品? 解空间:{(0,0,0),(0,0,1),…,(1,1,1)}
分支限界法解决0/1背包问题
分支限界法思想概述 与回溯法区别 求解步骤 常见的两种分支限界法 0-1背包问题
分支限界法的基本思想
分支限界法基本思想

分支限界法常以广度优先或以最小耗费(最大效益)优先的方式搜 索问题的解空间树。

算法设计与分析实验报告——基于回溯法的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背包问题的多种解法

0_1背包问题的多种解法

页脚内容1一、 问题描述0/1背包问题:现有n 种物品,对1<=i<=n ,已知第i 种物品的重量为正整数W i ,价值为正整数V i ,背包能承受的最大载重量为正整数W ,现要求找出这n 种物品的一个子集,使得子集中物品的总重量不超过W 且总价值尽量大。

(注意:这里对每种物品或者全取或者一点都不取,不允许只取一部分)二、 算法分析根据问题描述,可以将其转化为如下的约束条件和目标函数:于是,问题就归结为寻找一个满足约束条件(1),并使目标函数式(2)达到最大的解向量),......,,,(321n x x x x X =。

首先说明一下0-1背包问题拥有最优解。

假设),......,,,(321n x x x x 是所给的问题的一个最优解,则),......,,(32n x x x 是下面问题的一个最优解:∑∑==⎪⎩⎪⎨⎧≤≤∈-≤ni i i ini i i x v n i x x w W x w 2211max )2}(1,0{。

如果不是的话,设),......,,(32n y y y 是这个问题的一个最优解,则∑∑==>n i ni ii ii xv y v 22,且∑=≤+n i i i W y w x w 211。

因此,∑∑∑====+>+ni i i n i n i i i i i x v x v x v y v x v 1221111,这说明),........,,,(321n y y y x 是所给的0-1背包问题比),........,,,(321n x x x x 更优的解,从而与假设矛盾。

穷举法:用穷举法解决0-1背包问题,需要考虑给定n 个物品集合的所有子集,找出所有可能的子集(总重量不超过背包重量的子集),计算每个子集的总重量,然后在他们中找到价值最大的子集。

由于程序过于简单,在这里就不再给出,用实例说明求解过程。

下面给出了4个物品和一个容量为10的背包,下图就是用穷举法求解0-1背包问题的过程。

算法 0-1背包问题教学教材

算法 0-1背包问题教学教材

算法0-1背包问题一、实验目的与要求掌握回溯法、分支限界法的原理,并能够按其原理编程实现解决0-1背包问题,以加深对回溯法、分支限界法的理解。

1.要求分别用回溯法和分支限界法求解0-1背包问题;2.要求交互输入背包容量,物品重量数组,物品价值数组;3.要求显示结果。

二、实验方案在选择装入背包的物品时,对每种物品i只有2种选择,即装入背包或不装入背包。

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

三、实验结果和数据处理1.用回溯法解决0-1背包问题:代码:import java.util.*;public class Knapsack{private double[] p,w;//分别代表价值和重量private int n;private double c,bestp,cp,cw;private int x[]; //记录可选的物品private int[] cx;public Knapsack (double pp[],double ww[],double cc){this.p=pp;this.w=ww;this.n=pp.length-1;this.c=cc;this.cp=0;this.cw=0;this.bestp=0;x=new int[ww.length];cx=new int[pp.length];}void Knapsack(){backtrack(0);}void backtrack(int i){if(i>n){ //判断是否到达了叶子节点if(cp>bestp){for(int j=0;j<x.length;j++)x[j]=cx[j];bestp=cp;}return;}if(cw+w[i]<=c){//搜索右子树cx[i]=1;cw+=w[i];cp+=p[i];backtrack(i+1);cw-=w[i];cp-=p[i];}cx[i]=0;backtrack(i+1); //检查左子树}void printResult(){System.out.println("回溯法");System.out.println("物品个数:n=4");System.out.println("背包容量:c=7");System.out.println("物品重量数组:w= {3,5,2,1}"); System.out.println("物品价值数组:p= {9,10,7,4}"); System.out.println("最优值:="+bestp);System.out.println("选中的物品是:");for(int i=0;i<x.length;i++){System.out.print(x[i]+" ");}}public static void main(String[] args){double p[]={9,10,7,4};double w[]={3,5,2,1};int maxweight=7;Knapsack ks=new Knapsack(p,w,maxweight);ks.Knapsack(); //回溯搜索ks.printResult();}}运行结果:2.用优先队列式分支限界法解决0-1背包问题:代码:public class Knapsack{static double c;static int n;static double w[];static double p[];static double cw;static double cp;static int bestX[];static MaxHeap heap;//上界函数bound计算结点所相应价值的上界private static double bound(int i){double cleft=c-cw;double b=cp;while(i<=n&&w[i]<=cleft){cleft=cleft-w[i];b=b+p[i];i++;}//装填剩余容量装满背包if(i<=n)b=b+p[i]/w[i]*cleft;return b;}//addLiveNode将一个新的活结点插入到子集树和优先队列中private static void addLiveNode(double up,double pp,double ww,int lev,BBnode par,boolean ch){//将一个新的活结点插入到子集树和最大堆中BBnode b=new BBnode(par,ch);HeapNode node =new HeapNode(b,up,pp,ww,lev);heap.put(node);}private static double MaxKnapsack(){//优先队列式分支限界法,返回最大价值,bestx返回最优解BBnode enode=null;int i=1;double bestp=0;//当前最优值double up=bound(1);//当前上界while(i!=n+1){//非叶子结点//检查当前扩展结点的左儿子子结点double wt=cw+w[i];if(wt<=c){if(cp+p[i]>bestp)bestp=cp+p[i];addLiveNode(up,cp+p[i],cw+w[i],i+1,enode,true);}up=bound(i+1);if(up>=bestp)addLiveNode(up,cp,cw,i+1,enode,false);HeapNode node =(HeapNode)heap.removeMax();enode=node.liveNode;cw=node.weight;cp=node.profit;up=node.upperProfit;i=node.level;}for(int j=n;j>0;j--){bestX[j]=(enode.leftChild)?1:0;enode=enode.parent;}return cp;}public static double Knapsack(double pp[],double ww[],double cc,int xx[]) {//返回最大值,bestX返回最优解c=cc;n=pp.length-1;//定义以单位重量价值排序的物品数组Element q[]=new Element[n];double ws=0.0;double ps=0.0;for(int i=0;i<n;i++){q[i]=new Element(i+1,pp[i+1]/ww[i+1]);ps=ps+pp[i+1];ws=ws+ww[i+1];}if(ws<=c)return ps;}p=new double[n+1];w=new double[n+1];for(int i=0;i<n;i++){p[i+1]=pp[q[i].id];w[i+1]=ww[q[i].id];}cw=0.0;cp=0.0;bestX = new int[n+1];heap = new MaxHeap(n);double bestp = MaxKnapsack();for(int j=0;j<n;j++)xx[q[j].id]=bestX[j+1];return bestp;}public static void main(String [] args){double w[]=new double[5];w[1]=3;w[2]=5;w[3]=2;w[4]=1;double p[]=new double[5];p[1]=9;p[2]=10;p[3]=7;p[4]=4;double c=7;int x[] = new int[5];double m = Knapsack(p,w,c,x);System.out.println("优先队列式分支限界法:");System.out.println("物品个数:n=4");System.out.println("背包容量:c=7");System.out.println("物品重量数组:w= {3,5,2,1}"); System.out.println("物品价值数组:p= {9,10,7,4}"); System.out.println("最优值:="+m);System.out.println("选中的物品是:");for(int i=1;i<=4;i++)System.out.print(x[i]+" ");}//子空间中节点类型class BBnode{BBnode parent;//父节点boolean leftChild;//左儿子节点标志BBnode(BBnode par,boolean ch){parent=par;leftChild=ch;}}class HeapNode implements Comparable{BBnode liveNode; // 活结点double upperProfit; //结点的价值上界double profit; //结点所相应的价值double weight; //结点所相应的重量int level; // 活结点在子集树中所处的层次号//构造方法public HeapNode(BBnode node, double up, double pp , double ww,int lev) {liveNode = node;upperProfit = up;profit = pp;weight = ww;level = lev;}public int compareTo(Object o){double xup = ((HeapNode)o).upperProfit;if(upperProfit < xup)return -1;if(upperProfit == xup)return 0;elsereturn 1;}}class Element implements Comparable{int id;double d;public 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;}}class MaxHeap{static HeapNode [] nodes;static int nextPlace;static int maxNumber;public MaxHeap(int n){maxNumber = (int)Math.pow((double)2,(double)n); nextPlace = 1;//下一个存放位置nodes = new HeapNode[maxNumber];}public static void put(HeapNode node){nodes[nextPlace] = node;nextPlace++;heapSort(nodes);}public static HeapNode removeMax(){HeapNode tempNode = nodes[1];nextPlace--;nodes[1] = nodes[nextPlace];heapSort(nodes);return tempNode;}private static void heapAdjust(HeapNode [] nodes,int s,int m) {HeapNode rc = nodes[s];for(int j=2*s;j<=m;j*=2){if(j<m&&nodes[j].upperProfit<nodes[j+1].upperProfit) ++j;if(!(rc.upperProfit<nodes[j].upperProfit))break;nodes[s] = nodes[j];s = j;}nodes[s] = rc;}private static void heapSort(HeapNode [] nodes){for(int i=(nextPlace-1)/2;i>0;--i){heapAdjust(nodes,i,nextPlace-1);}}}运行结果:3.用队列式分支限界法解决0-1背包问题:代码:#include<stdio.h>#include<stdlib.h>#define MAXNUM 100struct node{int step;double price;double weight;double max, min;unsigned long po;};typedef struct node DataType;struct SeqQueue{ /* 顺序队列类型定义 */int f, r;DataType q[MAXNUM];};typedef struct SeqQueue *PSeqQueue;PSeqQueue createEmptyQueue_seq( void ){PSeqQueue paqu;paqu = (PSeqQueue)malloc(sizeof(struct SeqQueue));if (paqu == NULL)printf("Out of space!! \n");elsepaqu->f = paqu->r = 0;return paqu;}int isEmptyQueue_seq( PSeqQueue paqu ){return paqu->f == paqu->r;}/* 在队列中插入一元素x */void enQueue_seq( PSeqQueue paqu, DataType x ) {if((paqu->r + 1) % MAXNUM == paqu->f)printf( "Full queue.\n" );else{paqu->q[paqu->r] = x;paqu->r = (paqu->r + 1) % MAXNUM;}}/* 删除队列头元素 */void deQueue_seq( PSeqQueue paqu ){if( paqu->f == paqu->r )printf( "Empty Queue.\n" );elsepaqu->f = (paqu->f + 1) % MAXNUM; }/* 对非空队列,求队列头部元素 */DataType frontQueue_seq( PSeqQueue paqu ){return (paqu->q[paqu->f]);}/* 物品按性价比从新排序*/void sort(int n, double p[], double w[]){int i, j;for (i = 0; i < n-1; i++)for (j = i; j < n-1; j++){double a = p[j]/w[j];double b = p[j+1]/w[j+1];if (a < b){double temp = p[j];p[j] = p[j+1];p[j+1] = temp;temp = w[j];w[j] = w[j+1];w[j+1] = temp;}}}/* 求最大可能值*/double up(int k, double m, int n, double p[], double w[]) {int i = k;double s = 0;while (i < n && w[i] < m){m -= w[i];s += p[i];i++;}if (i < n && m > 0){s += p[i] * m / w[i];i++;}return s;}/* 求最小可能值*/double down(int k, double m, int n, double p[], double w[]) {int i = k;double s = 0;while (i < n && w[i] <= m){m -= w[i];s += p[i];i++;}return s;}/* 用队列实现分支定界算法*/double solve(double m, int n, double p[], double w[], unsigned long* po) {double min;PSeqQueue q = createEmptyQueue_seq();DataType x = {0,0,0,0,0,0};sort(n, p, w);x.max = up(0, m, n, p, w);x.min = min = down(0, m, n, p, w);if (min == 0) return -1;enQueue_seq(q, x);while (!isEmptyQueue_seq(q)){int step;DataType y;x = frontQueue_seq(q);deQueue_seq(q);if (x.max < min) continue;step = x.step + 1;if (step == n+1) continue;y.max = x.price + up(step, m - x.weight, n, p, w);if (y.max >= min){y.min = x.price + down(step, m-x.weight, n, p, w); y.price = x.price;y.weight = x.weight;y.step = step;y.po = x.po << 1;if (y.min >= min){min = y.min;if (step == n) *po = y.po;}enQueue_seq(q, y);}if (x.weight+w[step-1]<= m){y.max = x.price + p[step-1]+up(step, m-x.weight-w[step-1], n, p, w);if (y.max >= min) {y.min = x.price + p[step-1] +down(step, m-x.weight-w[step-1], n, p, w); y.price = x.price + p[step-1];y.weight = x.weight + w[step-1];y.step = step;y.po = (x.po << 1) + 1;if (y.min >= min){min = y.min;if (step == n) *po = y.po;}enQueue_seq(q, y);}}}return min;}#define n 4double m = 7;double p[n] = {9, 10, 7, 4};double w[n] = {3, 5, 1, 2};int main(){int i;double d;unsigned long po;d = solve(m, n, p, w, &po);if (d == -1)printf("No solution!\n");else{for (i = 0; i < n; i++)printf("x%d 为 %d\n", i + 1, ((po & (1<<(n-i-1))) != 0)); printf("最优值是:%f\n", d);}getchar();return 0;}运行结果:。

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背包问题:给定种物品和一个容量为的背包,物品的重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背包问题(计算机算法设计与分析实验报告)

回溯法、分支限界法解0-1背包问题(计算机算法设计与分析实验报告)
BBnode enode =null;
inti = 1;
doublebestp = 0.0;
doubleup = bound(1);
while(i !=n+ 1) {
doublewt =cw+w[i];
//检查当前扩展节点的左儿子节点
if(wt <=c) {
if(cp+p[i] > bestp) {
}
do{
System.out.println("请输入背包的容量:");
input = in.readLine().trim();
input = in.readLine().replaceAll(" ","");
}while(input.equals(""));
if(input.equals("2")){
w=newdouble[n+ 1];
for(inti = 1; i <=n; i++) {
p[i] = pp[q[i - 1].id- 1];
w[i] = ww[q[i - 1].id- 1];
}
backtrack(1);
returnbestp;
}
//回溯过程
privatevoidbacktrack(inti) {
c= cc;
n= pp.length;
Element[] q =newElement[n];
doublews = 0.0;
doubleps = 0.0;
for(inti = 0; i <n; i++) {
q[i] =newElement(i + 1, pp[i] / ww[i]);
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

华北水利水电学院数据结构与算法分析实验报告2009 ~2010 学年第 1 学期2009 级计算机专业班级:200915326 学号:200915326 姓名:郜莉洁一、实验题目:分别用回溯法和分支限界法求解0-1背包问题二、实验内容:0-1背包问题:给定n种物品和一个背包。

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

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

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

三、程序源代码:A:回溯法:// bag1.cpp : Defines the entry point for the console application.//#include "stdafx.h"#include <iostream.h>#define MaxSize 100 //最多物品数int limitw; //限制的总重量int maxwv=0; //存放最优解的总价值int maxw;int n; //实际物品数int option[MaxSize]; // 存放最终解int op[MaxSize]; //存放临时解struct {int weight;int value;}a[MaxSize]; //存放物品数组void Knap( int i, int tw, int tv) //考虑第i个物品{int j;if(i>=n) //找到一个叶子结点{if (tw<=limitw && tv>maxwv) //找到一个满足条件地更优解,保存它{maxwv=tv; maxw=tw;for(j=0;j<n;j++) option[j]=op[j];}}else{op[i]=1; //选取第I个物品Knap(i+1,tw+a[i].weight, tv+a[i].value);op[i]=0; //不选取第I个物品,回溯Knap(i+1,tw,tv);}}int main(int argc, char* argv[]){int j;n=3; //3物品a[0].weight=16;a[0].value=45;a[1].weight=15;a[1].value=25;a[2].weight=15;a[2].value=25;//a[3].weight=1;a[3].value=1;limitw=30; //限制重量不超过30 Knap(0,0,0);cout<<"最佳装填方案是:"<<endl;for(j=0;j<n;j++)if(option[j]==1)cout<<"第"<<j+1<<"种物品"<<endl;cout<<"总重量="<<maxw<<",总价值="<<maxwv<<endl;return 0;}回溯法测试结果:测试数据:物品一:重量:16,价格:45;物品二:重量:15,价格:25;物品三:重量:15,价格:25;B:分支限界法:#include <stdio.h>#include<malloc.h>#define MaxSize 100 //最多结点数typedef struct QNode{float weight;float value;int ceng;struct QNode *parent;bool leftChild;}QNode,*qnode; //存放每个结点typedef struct{qnode Q[MaxSize];int front,rear;}SqQueue; //存放结点的队列SqQueue sq;float bestv=0; //最优解int n=0; //实际物品数float w[MaxSize]; //物品的重量float v[MaxSize]; //物品的价值int bestx[MaxSize]; // 存放最优解qnode bestE;void InitQueue(SqQueue &sq ) //队列初始化{sq.front=1;sq.rear=1;}bool QueueEmpty(SqQueue sq) //队列是否为空if(sq.front==sq.rear)return true;elsereturn false;}void EnQueue(SqQueue &sq,qnode b)//入队{if(sq.front==(sq.rear+1)%MaxSize){printf("队列已满!");return ;}sq.Q[sq.rear]=b;sq.rear=(sq.rear+1)%MaxSize;}qnode DeQueue(SqQueue &sq)//出队{qnode e;if(sq.front==sq.rear){printf("队列已空!");return 0;}e=sq.Q[sq.front];sq.front=(sq.front+1)%MaxSize;return e;}void EnQueue1(float wt,float vt, int i ,QNode *parent, bool leftchild)qnode b;if (i==n) //可行叶子结点{if (vt==bestv){bestE=parent;bestx[n]=(leftchild)?1:0;}return;}b=(qnode)malloc(sizeof(QNode)); //非叶子结点b->weight=wt;b->value=vt;b->ceng=i;b->parent=parent;b->leftChild=leftchild;EnQueue(sq,b);}void maxLoading(float w[],float v[],int c){float wt=0;float vt=0;int i=1; //当前的扩展结点所在的层float ew=0; //扩展节点所相应的当前载重量float ev=0; //扩展结点所相应的价值qnode e=NULL;qnode t=NULL;InitQueue(sq);EnQueue(sq,t); //空标志进队列while (!QueueEmpty(sq)){wt=ew+w[i];vt=ev+v[i];if (wt <= c){if(vt>bestv)bestv=vt;EnQueue1(wt,vt,i,e,true); // 左儿子结点进队列}EnQueue1(ew,ev,i,e,false); //右儿子总是可行;e=DeQueue(sq); // 取下一扩展结点if (e == NULL){if (QueueEmpty(sq)) break;EnQueue(sq,NULL); // 同层结点尾部标志e=DeQueue(sq); // 取下一扩展结点i++;}ew=e->weight; //更新当前扩展结点的值ev=e->value;}printf("最优取法为:\n");for( int j=n-1;j>0;j--) //构造最优解{bestx[j]=(bestE->leftChild?1:0);bestE=bestE->parent;}for(int k=1;k<=n;k++){if(bestx[k]==1)printf("\n物品%d:重量:%.1f,价值:%.1f\n",k,w[k],v[k]);}printf("\n");printf("最优价值为:%.1f\n\n",bestv);}void main(){int c;float ewv[MaxSize];printf(" //////////////////// 0-1背包问题分枝限界法/////////////////////\n\n");printf("请输入物品的数量:\n");scanf("%d",&n);printf("请输入背包的最大承重量:\n");scanf("%d",&c);printf("\n请输入物品的重量和单位重量价值:\n\n");for(int i=1;i<=n;i++){printf("物品%d:",i);scanf("%f%f",&w[i],&ewv[i]);v[i]=w[i]*ewv[i];printf("\n");}maxLoading(w, v, c);}分支限界法测试结果:五、小结(包括收获、心得体会、存在的问题及解决问题的方法、建议等)注:内容一律使用宋体五号字,单倍行间距,不得少于100字。

1 通过这次试验是我对数据结构有了进一步的了解,可以通过算法解决实际问题(背包问题)。

2在用分支限界法实现问题时遇到了有关队列的问题,通过上网搜索,问老师得以解决。

3在老师有计划的指导安排下,我的编程能力突飞猛进,在此,对老师深表感谢!!。

相关文档
最新文档