背包问题回溯法回朔法、分支限界法解0-1背包问题程序,要完整的,可执行的。限JAVA或C语言编写

背包问题回溯法  时间:2021-09-13  阅读:()

用回溯法做0-1背包问题,这两行(程序中标注)是干嘛?为什么又要减?

看来新手对于回溯还是比较难以理解的,其实很简单啊 ,就是一个递归啊,递归啊楼主就是自己调用自己啊,自己调用自己啊,你初中就学过了啊。

比如 f[i] = f[i-1] + 3; 好了现在我跟你说f[0] = 1 , 那么f[10]怎么求呢,就是不断的迭代那个公式啊,写成代码就是 int?f(int?i) { ????if(i?==?0)?return?1; ????return?f[i-1]?+?3; }i = 0 是整个递归的边界,就是到i = 0 的时候不继续迭代了,直接返回了,然后一层一层返回。

比如求f(2) = f(1) + 3 = (f(0)+3) +3 ,其中f[0] = 1,好了不断往左迭代就能算出f(2)了。

好了我知道楼主要说我废话了,想说你问的又不是这个是吧,但是真的无关了? 我们再来看看你给的代码吧 void?backtrack(int?i) { ????double?bound(int?j);?//声明后面要用到的限界函数 ????//到达叶子结点 ????if(i>n)//这个就是边界,因为这边他没有调用自己而是直接返回了, ????对应了我们上面的i?=?0;递归一定要有边界! ????{ ???????bestp=cp; ???????return; ????} ????//当不是边界的时候呢,既然是递归那肯定就是自己调自己了 ????if(cw+w[i]<=c) ????{ ????????cw+=w[i]; ????????cp+=p[i]; ????????put[i]=1; ????????backtrack(i+1);//这边就在自己调用自己了,下边那个backtrack(i+1)也一样 ????????cw-=w[i];//好了楼主的问题来了,这边在干吗?好了要知道这边在干吗,必须要知道这条语句什么时候执行啊!那么这条语句什么时候执行呢?当然是上面那条语句执行完毕之后执行啊,楼主也看到了上面是个递归函数,对应到我们上面的递推公式,他要一直自己调用自己啊,直到边界。

那么在这个函数里,边界就是上面的i>n,那么究竟是什么意思呢?也就是说这执行这条语句之前,我都已经搜索到叶子节点了,而且已经返回了,就是说当取了第i这个物品的时候呢,后面所有的情况我都已经处理完了。

那么我是不是该处理当不取第i这个物品了呢,那么我就要把刚刚取了第i个物品的重量和价值减掉,因为我现在要处理的是不取他们,所以这边把刚刚加的给减掉还了,这就是所谓的回溯,楼主好好体会一下,其实没有那么复杂的,你想啊backtrack(int?i)这个函数是在干吗,不就是计算以i为父节点的子树能取到的最大价值么,那么backtrack(i+1)就是计算以i+1为父节点的子树能取到的最大值啊。

那么我取了i节点去计算一下backtrack(i+1),然后我在不取i节点去计算一下backtrack(i+1),整个程序大概就是这个思想,你的问题就是在不取i节点的时候把当时取i节点的加上去的值减掉还原成不取i节点时的情况,这也是回溯的中心思想。

其实你还可以这么分析:假设这边只有两层,也就是说只有2件物品,那么是不是很好跟踪程序呢,这叫降低规模。

????????cp-=p[i];// ????} ????//符合条件才搜索右子树 ????if(bound(i+1)>bestp) ????????backtrack(i+1); }

背包问题的算法

3.2 背包问题 背包问题有三种 1.部分背包问题 一个旅行者有一个最多能用m公斤的背包,现在有n种物品,它们的总重量分别是W1,W2,...,Wn,它们的总价值分别为C1,C2,...,Cn.求旅行者能获得最大总价值。

解决问题的方法是贪心算法:将C1/W1,C2/W2,...Cn/Wn,从大到小排序,不停地选择价值与重量比最大的放人背包直到放满为止. 2.0/1背包 一个旅行者有一个最多能用m公斤的背包,现在有n件物品,它们的重量分别是W1,W2,...,Wn,它们的价值分别为C1,C2,...,Cn.若每种物品只有一件求旅行者能获得最大总价值。

<1>分析说明: 显然这个题可用深度优先方法对每件物品进行枚举(选或不选用0,1控制). 程序简单,但是当n的值很大的时候不能满足时间要求,时间复杂度为O(2n)。

按递归的思想我们可以把问题分解为子问题,使用递归函数 设 f(i,x)表示前i件物品,总重量不超过x的最优价值 则 f(i,x)=max(f(i-1,x-W[i])+C[i],f(i-1,x)) f(n,m)即为最优解,边界条件为f(0,x)=0 ,f(i,0)=0; 动态规划方法(顺推法)程序如下: 程序如下: program knapsack02; const maxm=200;maxn=30; type ar=array[1..maxn] of integer; var m,n,j,i:integer; c,w:ar; f:array[0..maxn,0..maxm] of integer; function max(x,y:integer):integer; begin if x>y then max:=x else max:=y; end; begin readln(m,n); for i:= 1 to n do readln(w[i],c[i]); for i:=1 to m do f(0,i):=0; for i:=1 to n do f(i,0):=0; for i:=1 to n do for j:=1 to m do begin if j>=w[i] then f[i,j]:=max(f[i-1,j-w[i]]+c[i],f[i-1,j]) else f[i,j]:=f[i-1,j]; end; writeln(f[n,m]); end. 使用二维数组存储各子问题时方便,但当maxm较大时如maxn=2000时不能定义二维数组f,怎么办,其实可以用一维数组,但是上述中j:=1 to m 要改为j:=m downto 1,为什么?请大家自己解决。

3.完全背包问题 一个旅行者有一个最多能用m公斤的背包,现在有n种物品,每件的重量分别是W1,W2,...,Wn, 每件的价值分别为C1,C2,...,Cn.若的每种物品的件数足够多. 求旅行者能获得的最大总价值。

本问题的数学模型如下: 设 f(x)表示重量不超过x公斤的最大价值, 则 f(x)=max{f(x-w[i])+c[i]} 当x>=w[i] 1<=i<=n 程序如下:(顺推法) program knapsack04; const maxm=2000;maxn=30; type ar=array[0..maxn] of integer; var m,n,j,i,t:integer; c,w:ar; f:array[0..maxm] of integer; begin readln(m,n); for i:= 1 to n do readln(w[i],c[i]); f(0):=0; for i:=1 to m do for j:=1 to n do begin if i>=w[j] then t:=f[i-w[j]]+c[j]; if t>f[i] then f[i]:=t end; writeln(f[m]); end.

回朔法、分支限界法解0-1背包问题程序,要完整的,可执行的。限JAVA或C语言编写

Java回溯法: package sun; import java.util.*; public class Knapsack0{ /* 用回溯法解决0-1背包问题 */ private double[] p,w;//分别代表价值和重量 private int n; private double c,bestp,cp,cw; private int x[]; //记录可选的物品 private int[] cx; public Knapsack0(double pp[],double ww[],){ this.p=pp;this.w=ww;this.n=pp.length-1; ;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=5"); System.out.println("*****背包容量:c=10"); System.out.println("*****物品重量数组:ww= {2,2,6,5,4}"); System.out.println("*****物品价值数组:vv= {6,3,5,4,6}"); 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[]={6,3,5,4,6}; double w[]={2,2,6,5,4}; int maxweight=10; Knapsack0 ks=new Knapsack0(p,w,maxweight); ks.knapsack(); //回溯搜索 ks.printResult(); } } 分支限界法: package sun; public class knapsack1 { 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[],,int xx[]){ //返回最大值,bestX返回最优解 ; 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[6]; w[1]=2;w[2]=2;w[3]=6;w[4]=5;w[5]=4; double v[]=new double[6]; v[1]=6;v[2]=3;v[3]=4;v[4]=5;v[5]=6; double c=10; int x[] = new int[6]; double m = knapsack(v,w,c,x); System.out.println("*****分支限界法*****"); System.out.println("*****物品个数:n=5"); System.out.println("*****背包容量:c=10"); System.out.println("*****物品重量数组:w= {2,2,6,5,4}"); System.out.println("*****物品价值数组:v= {6,3,5,4,6}"); System.out.println("*****最优值:="+m); System.out.println("*****选中的物品是:"); for(int i=1;i<=5;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 pareTo(Object o) { double xup = ((HeapNode)o).upperProfit; if(upperProfit < xup) return -1; if(upperProfit == xup) return 0; else return 1; } } class Element implements Comparable{ int id; double d; public Element(int idd,double dd){ id=idd; d=dd; } public pareTo(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); } } } 不知道你是哪的学生, 此乃郑州轻工业学院考试试题, 并且还未上交, 抄的时候小心点, 参考一下就可以了, 不要全抄, 版权所有违者必究!!!!!!!!! 哈哈哈哈 !!!

SugarHosts新增Windows云服务器sugarhosts六折无限流量云服务器六折优惠

SugarHosts糖果主机商我们较早的站长们肯定是熟悉的,早年是提供虚拟主机起家的,如今一直还在提供虚拟主机,后来也有增加云服务器、独立服务器等。数据中心涵盖美国、德国、香港等。我们要知道大部分的海外主机商都只提供Linux系统云服务器。今天,糖果主机有新增SugarHosts夏季六折的优惠,以及新品Windows云服务器/云VPS上线。SugarHosts Windows系统云服务器有区分限制...

欧路云:美国200G高防云-10元/月,香港云-15元/月,加拿大480G高防云-23元/月

欧路云 主要运行弹性云服务器,可自由定制配置,可选加拿大的480G超高防系列,也可以选择美国(200G高防)系列,也有速度直逼内地的香港CN2系列。所有配置都可以在下单的时候自行根据项目 需求来定制自由升级降级 (降级按天数配置费用 退款回预存款)。由专业人员提供一系列的技术支持!官方网站:https://www.oulucloud.com/云服务器(主机测评专属优惠)全场8折 优惠码:zhuji...

RAKsmart 年中活动 独立服务器限时$30秒杀 VPS主机低至$1.99

RAKsmart 虽然是美国主机商,但是商家的主要客户群还是在我们国内,于是我们可以看到每次的国内节日促销活动期间商家也会发布促销。包括这次年中大促活动,RAKsmart商家也有发布为期两个月的年终活动,其中有商家擅长的独立服务器和便宜VPS主机。服务器包括站群服务器、特价服务器、高达10G带宽不限制流量的美国服务器。商家优惠活动,可以看到对应商品的优惠,同时也可以使用 优惠码 RAKBL9 同时...

背包问题回溯法为你推荐
expire英语:expire能用来说人去世了吗按键精灵教程怎么使用按键精灵antiarpantiARP功能介绍一下活跃网络移动大V网是什么意思?摇一摇周边什么是微信摇一摇周边?淘宝推广网站谁有好的淘宝推广网站介绍下哦!或推广技巧!里程碑2摩托罗拉里程碑2怎么样修复网络lspwin 7,lsp修复无法上网对联广告代码HTMl教程:实现网页左右两侧居中的对联广告代码约束是什么意思爱不约束是什么意思
深圳虚拟主机 老域名 电信服务器租用 域名服务器是什么 3322免费域名 ftp空间 本网站服务器在美国维护 pw域名 香港cdn la域名 免费ftp空间 创宇云 北京主机 softbank邮箱 股票老左 adroit 支持外链的相册 drupal安装 阿里云官方网站 百度云加速 更多