ImageVerifierCode 换一换
格式:DOCX , 页数:16 ,大小:21.10KB ,
资源ID:6460758      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/6460758.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(01背包问题的各种算法求解.docx)为本站会员(b****6)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

01背包问题的各种算法求解.docx

1、01背包问题的各种算法求解一.动态规划求解0-1背包问题 /*/ /* 0-1背包问题: /* 给定n种物品和一个背包 /* 物品i的重量为wi,其价值为vi /* 背包的容量为c /* 应如何选择装入背包的物品,使得装入背包中的物品 /* 的总价值最大? /* 注:在选择装入背包的物品时,对物品i只有两种选择, /* 即装入或不装入背包。不能将物品i装入多次,也 /* 不能只装入部分的物品i。 /* /* 1. 0-1背包问题的形式化描述: /* 给定c0, wi0, vi0, 0=i=n,要求找到一个n元的 /* 0-1向量(x1, x2, ., xn), 使得: /* max sum_i

2、=1 to n (vi*xi),且满足如下约束: /* (1) sum_i=1 to n (wi*xi) = c /* (2) xi0, 1, 1=i=n /* /* 2. 0-1背包问题的求解 /* 0-1背包问题具有最优子结构性质和子问题重叠性质,适于 /* 采用动态规划方法求解 /* /* 2.1 最优子结构性质 /* 设(y1,y2,.,yn)是给定0-1背包问题的一个最优解,则必有 /* 结论,(y2,y3,.,yn)是如下子问题的一个最优解: /* max sum_i=2 to n (vi*xi) /* (1) sum_i=2 to n (wi*xi) = c - w1*y1 /*

3、 (2) xi0, 1, 2=i sum_i=2 to n (vi*yi) /* 且,w1*y1 + sum_i=2 to n (wi*zi) sum_i=1 to n (vi*yi) /* w1*y1 + sum_i=2 to n (wi*zi) = c /* 这说明:(y1,z2,z3,.zn)是所给0-1背包问题的更优解,那么 /* 说明(y1,y2,.,yn)不是问题的最优解,与前提矛盾,所以最优 /* 子结构性质成立。 /* /* 2.2 子问题重叠性质 /* 设所给0-1背包问题的子问题 P(i,j)为: /* max sum_k=i to n (vk*xk) /* (1) sum

4、_k=i to n (wk*xk) = j /* (2) xk0, 1, i=k=wn /* m(n,j) = 0, 0=jwn /* b. 递归式 m(i,j) /* /背包容量为j、可选物品为i,i+1,.,n /* /如果背包容量jwi,则根本装不进物品i,所以有: /* m(i,j) = m(i+1,j), 0=j=wi,则在不装物品i和装入物品i之间做出选择 /* 不装物品i的最优值:m(i+1,j) /* 装入物品i的最优值:m(i+1, j-wi) + vi /* 所以: /* m(i,j) = max m(i+1,j), m(i+1, j-wi) + vi, j=wi /* /

5、*/ #define max(a,b) (a) (b) ? (a) : (b) #define min(a,b) (a) (b) ? (a) : (b) template void Knapsack(Type* v, int *w, int c, int n, Type *m) /递归初始条件 int jMax = min(wn - 1, c); for (int j=0; j=jMax; j+) mnj = 0; for (j=wn; j=wi和0=j1; i-) jMax = min(wi - 1, c); for (int j=0; j=jMax; j+) mij = mi+1j; fo

6、r (j=wi; j= w1) m1c = max(m1c, m2c-w1+v1); template void TraceBack(Type *m, int *w, int c, int n, int* x) for (int i=1; in; i+) if(mic = mi+1c) xi = 0; else xi = 1; c -= wi; xn = (mnc)? 1:0; int main(int argc, char* argv) int n = 5; int w6 = -1, 2, 2, 6, 5, 4; int v6 = -1, 6, 3, 5, 4, 6; int c = 10;

7、 int *ppm = new int*n+1; for (int i=0; in+1; i+) ppmi = new intc+1; int x6; Knapsack(v, w, c, n, ppm); TraceBack(ppm, w, c, n, x); return 0; 二.贪心算法求解0-1背包问题 1.贪心法的基本思路: 从问题的某一个初始解出发逐步逼近给定的目标,以尽可能快的地求得更好的解。当达到某算法中的某一步不能再继续前进时,算法停止。 该算法存在问题: 1).不能保证求得的最后解是最佳的; 2).不能用来求最大或最小解问题; 3).只能求满足某些约束条件的可行解的范围。

8、实现该算法的过程: 从问题的某一初始解出发; while 能朝给定总目标前进一步 do 求出可行解的一个解元素; 由所有解元素组合成问题的一个可行解; 2.例题分析 1).背包问题有一个背包,背包容量是M=150。有7个物品,物品可以分割成任意大小。 要求尽可能让装入背包中的物品总价值最大,但不能超过总容量。 物品 A B C D E F G 重量 35 30 60 50 40 10 25 价值 10 40 30 50 35 40 30 分析: 目标函数: pi最大 约束条件是装入的物品总重量不超过背包容量:wi=M( M=150) (1)根据贪心的策略,每次挑选价值最大的物品装入背包,得到的

9、结果是否最优? (2)每次挑选所占空间最小的物品装入是否能得到最优解? (3)每次选取单位容量价值最大的物品,成为解本题的策略。 (环境:c+) #include #define max 100 /最多物品数 void sort (int n,float amax,float bmax) /按价值密度排序 int j,h,k; float t1,t2,t3,cmax; for(k=1;k=n;k+) ck=ak/bk; for(h=1;hn;h+) for(j=1;j=n-h;j+) if(cjcj+1) t1=aj;aj=aj+1;aj+1=t1; t2=bj;bj=bj+1;bj+1=t2

10、; t3=cj;cj=cj+1;cj+1=t3; void knapsack(int n,float limitw,float vmax,float wmax,int xmax) float c1; /c1为背包剩余可装载重量 int i; sort(n,v,w); /物品按价值密度排序 c1=limitw; for(i=1;ic1)break; xi=1; /xi为1时,物品i在解中 c1=c1-wi; void main() int n,i,xmax; float vmax,wmax,totalv=0,totalw=0,limitw; coutn limitw; for(i=1;i=n;i

11、+) xi=0; /物品选择情况表初始化为0 cout请依次输入物品的价值:endl; for(i=1;ivi; coutendl; cout请依次输入物品的重量:endl; for(i=1;iwi; coutendl; knapsack (n,limitw,v,w,x); coutthe selection is:; for(i=1;i=n;i+) coutxi; if(xi=1) totalw=totalw+wi; coutendl; cout背包的总重量为:totalwendl; /背包所装载总重量 cout背包的总价值为:totalvendl; /背包的总价值 三.回溯算法求解0-1背

12、包问题 1.0-l背包问题是子集选取问题。 一般情况下,0-1背包问题是NP难题。0-1背包 问题的解空间可用子集树表示。解0-1背包问题的回溯法与装载问题的回溯法类似。在搜索解空间树时,只要其左孩子结点是一个可行结点,搜索就进入其左子树。当右子树有可能包含最优解时才进入右子树搜索。否则将右子树剪去。设r是当前剩余物品价值总和;cp是当前价值;bestp是当前最优价值。当cp+rbestp时,可剪去右 子树。计算右子树中解的上界的更好方法是将剩余物品依其单位重量价值排序,然后 依次装入物品,直至装不下时,再装入该物品的一部分而装满背包。由此得到的价值是右子树中解的上界。 2.解决办法思路: 为

13、了便于计算上界,可先将物品依其单位重量价值从大到小排序,此后只要顺序考 察各物品即可。在实现时,由bound计算当前结点处的上界。在搜索解空间树时,只要其左孩子节点是一个可行结点,搜索就进入左子树,在右子树中有可能包含最优解时才进入右子树搜索。否则将右子树剪去。 回溯法是一个既带有系统性又带有跳跃性的搜索算法。它在包含问题的所有解的解空间树中,按照深度优先的策略,从根结点出发搜索解空间树。算法搜索至解空间树的任一结点时,总是先判断该结点是否肯定不包含问题的解。如果肯定不包含,则跳过对以该结点为根的子树的系统搜索,逐层向其祖先结点回溯。否则,进入该子树,继续按深度优先的策略进行搜索。回溯法在用来

14、求问题的所有解时,要回溯到根,且根结点的所有子树都已被搜索遍才结束。而回溯法在用来求问题的任一解时,只要搜索到问题的一个解就可以结束。这种以深度优先的方式系统地搜索问题的解的算法称为回溯法,它适用于解一些组合数较大的问题。 2.算法框架: a.问题的解空间:应用回溯法解问题时,首先应明确定义问题的解空间。问题的解空间应到少包含问题的一个(最优)解。 b.回溯法的基本思想:回溯法就从根结点出发,以深度优先的方式搜索整个解空间。根结点成为一个活结点,同时也成为当前的扩展结点。在当前的扩展结点处,搜索向纵深方向移至一个新结点。这个新结点就成为一个新的活结点,并成为当前扩展结点。如果在当前的扩展结点处

15、不能再向纵深方向移动,则当前扩展结点就成为死结点。换句话说,这个结点不再是一个活结点。此时,应往回移动(回溯)至最近的一个活结点处,并使这个活结点成为当前的扩展结点。回溯法即以这种工作方式递归地在解空间中搜索,直至找到所要求的解或解空间中已没有活结点时为止。 3.运用回溯法解题通常包含以下三个步骤: a.针对所给问题,定义问题的解空间; b.确定易于搜索的解空间结构; c.以深度优先的方式搜索解空间,并且在搜索过程中用剪枝函数避免无效搜索; #include using namespace std; class Knap friend int Knapsack(int p,int w,int

16、c,int n ); public: void print() for(int m=1;m=n;m+) coutbestxm ; coutendl; ; private: int Bound(int i); void Backtrack(int i); int c;/背包容量 int n; /物品数 int *w;/物品重量数组 int *p;/物品价值数组 int cw;/当前重量 int cp;/当前价值 int bestp;/当前最优值 int *bestx;/当前最优解 int *x;/当前解 ; int Knap:Bound(int i) /计算上界 int cleft=c-cw;/

17、剩余容量 int b=cp; /以物品单位重量价值递减序装入物品 while(i=n&wi=cleft) cleft-=wi; b+=pi; i+; /装满背包 if(in) if(bestpcp) for(int j=1;j=n;j+) bestxj=xj; bestp=cp; return; if(cw+wibestp)/搜索右子树 xi=0; Backtrack(i+1); class Object friend int Knapsack(int p,int w,int c,int n); public: int operator=a.d); private: int ID; float

18、 d; ; int Knapsack(int p,int w,int c,int n) /为Knap:Backtrack初始化 int W=0; int P=0; int i=1; Object *Q=new Objectn; for(i=1;i=n;i+) Qi-1.ID=i; Qi-1.d=1.0*pi/wi; P+=pi; W+=wi; if(W=c) return P;/装入所有物品 /依物品单位重量排序 float f; for( i=0;in;i+) for(int j=i;jn;j+) if(Qi.dQj.d) f=Qi.d; Qi.d=Qj.d; Qj.d=f; Knap K;

19、 K.p = new intn+1; K.w = new intn+1; K.x = new intn+1; K.bestx = new intn+1; K.x0=0; K.bestx0=0; for( i=1;i=n;i+) K.pi=pQi-1.ID; K.wi=wQi-1.ID; K.cp=0; K.cw=0; K.c=c; K.n=n; K.bestp=0; /回溯搜索 K.Backtrack(1); K.print(); delete Q; delete K.w; delete K.p; return K.bestp; void main() int *p; int *w; int

20、c=0; int n=0; int i=0; char k; cout0-1背包问题回溯法 endl; cout by zbqplayer endl; while(k) cout请输入背包容量(c):c; cout请输入物品的个数(n):n; p=new intn+1; w=new intn+1; p0=0; w0=0; cout请输入物品的价值(p):endl; for(i=1;ipi; cout请输入物品的重量(w):endl; for(i=1;iwi; cout最优解为(bestx):endl; cout最优值为(bestp):endl; coutKnapsack(p,w,c,n)end

21、l; couts 重新开始endl; coutq 退出k; 四.分支限界法求解0-1背包问题 1.问题描述:已知有N个物品和一个可以容纳M重量的背包,每种物品I的重量为WEIGHT,一个只能全放入或者不放入,求解如何放入物品,可以使背包里的物品的总效益最大。 2.设计思想与分析:对物品的选取与否构成一棵解树,左子树表示不装入,右表示装入,通过检索问题的解树得出最优解,并用结点上界杀死不符合要求的结点。 #include struct good int weight; int benefit; int flag;/是否可以装入标记 ; int number=0;/物品数量 int upbound

22、=0; int curp=0, curw=0;/当前效益值与重量 int maxweight=0; good *bag=NULL; void Init_good() bag=new good number; for(int i=0; inumber; i+) cout请输入第件i+1bagi.weight; cout请输入第件i+1bagi.benefit; bagi.flag=0;/初始标志为不装入背包 coutendl; int getbound(int num, int *bound_u)/返回本结点的c限界和u限界 for(int w=curw, p=curp; numnumber &

23、 (w+bagnum.weight)=maxweight; num+) w=w+bagnum.weight; p=w+bagnum.benefit; *bound_u=p+bagnum.benefit; return ( p+bagnum.benefit*(maxweight-w)/bagnum.weight) ); void LCbag() int bound_u=0, bound_c=0;/当前结点的c限界和u限界 for(int i=0; iupbound )/遍历左子树 upbound=bound_u;/更改已有u限界,不更改标志 if( getbound(i, &bound_u)bound_c )/遍历右子树 /若装入,判断右子树的c限界是否大于左子树根的c限界,是则装入 upbound=bound_u;/更改已有u限界 curp=curp+bagi.benefit; curw=curw+bagi.weight;/从已有重量和效益加上新物品 bagi.flag=1;/标记为装入 void Display() cout可以放入背包的物品的编号为:; for(int i=0; i

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1