综合设计性实验报告背包问题的多种算法设计与分析.docx
- 文档编号:5519861
- 上传时间:2022-12-18
- 格式:DOCX
- 页数:11
- 大小:19.57KB
综合设计性实验报告背包问题的多种算法设计与分析.docx
《综合设计性实验报告背包问题的多种算法设计与分析.docx》由会员分享,可在线阅读,更多相关《综合设计性实验报告背包问题的多种算法设计与分析.docx(11页珍藏版)》请在冰豆网上搜索。
综合设计性实验报告背包问题的多种算法设计与分析
0-1背包问题的多种算法设计与分析
一、实验内容和要求:
0-1背包问题是一例典型的组合优化的NP完全问题。
问题能够描述为:
给定一组共n个物品,每种物品都有自己的重量wi,i=1~n和价值vi,i=1~n,在限定的总重量(背包的容量C)内,如何选择才能使得选择物品的总价值之和最高。
选择最优的物品子集放置于给定背包中,最优子集对应n元解向量(x1,…xn),xi∈{0或1},因此命名为0-1背包问题。
0-1背包问题是许多问题的原型,但它又是一个NP完全问题。
此实验主要研究和实现n(0<=n<=200)和C(C<=2000,C为整数)都较大的情形,随机产生n个物品的重量向量wi(1<=wi<=100,wi为整数)和价值向量vi(1<=vi<=100,vi为整数)。
0-1背包问题能够用许多方式来求解,有些算法能够取得问题的精准最优解,有些仅能取得一个近似最优解。
本综合设计性实验要求用3种以上的方式求解0-1背包问题,取得精准最优解或近似最优解皆可,并对所采用的多种算法从运行时刻、寻觅是不是为最优解、能够求解的问题规模等方面进行对比和分析。
本课程讲述的算法思想都能够用来求解此问题,乃至本课程未涉及的许多算法也超级适合于求解此问题,学生能够先尝试先用本课程介绍的算法来实现和分析,学有余力或兴趣驱动下能够寻觅一些智能算法的资料来试一试。
涉及的方式能够有:
蛮力求解、递归求解、动态计划求解、贪婪求解、回溯法求解、广度优先的分支限界法求解,优先队列的启发式分支限界法、遗传算法、模拟退火算法、蚁群算法、粒子群算法等。
为方便调试,采用文件输入,标准输出(或文件输出也可)的形式。
数据输入的格式如下:
每组测试数据包括n+1行,第1行为C和n,表示背包容量为C且有n个物品,接下来n行为这n个物品的重量wi和价值vi。
背包容量和物品重量都为整数。
n,C,wi,vi范围如上所述。
输出两行。
第一行为所选物品的最大价值之和,第二行为装入背包的物品所对应的n元最优解向量(x1,…xn),xi∈{0或1}。
二、多种算法详细设计
1.贪婪算法
输入物品价值和重量。
别离用数组v[o..n]和w[0..n]来记录。
按照物品价值v[i]/w[i]由高到低对v[o..n]和w[0..n]进行排序。
然后把物品从1到n依次加入背包,直到装不下为止。
设c为背包容量,每次装一个物品,则c-=w[i],当前价值为value+=v[i],当c<=0时,停止加入物品,现在的value即为最优值。
对于背包问题,贪婪选择最终可取得最优解,但对于0-1背包问题,贪婪选择无法保证最终能将背包装满,部份闲置的背包空间使单位背包空间的价值降低了。
2.递归求解
1)0-1背包最优问题具有最优子结构性质。
设(y1,y2,...,yn)是所给0-1背包的一个最优解,则(y2,y3,...,yn)是除y1外的最优解。
2)设所给0-1背包问题的子问题的最优值为m(i,j),即m(i,j)是背包容量为j,可选物品为i,i+1,...,n时0-1背包问题的最优值。
由0-1背包的问题的最优子结构性质,能够成立计算m(i,j)的递归式如下:
m(i,j)=max{m(i+1,j),m(i+1,j-wi)+vi}j>=wi
=m(i+1,j)0<=j m(i,j)=vnj>=wn =00<=j 用二维数组m[i][j]存储m(i,j)的值。 按照递归式算出m[i][j]的值。 则m[1][c]是给出所要求的0-1背包问题的最优值。 相应的最优解可由算法Traceback计算如下。 若是m[1][c]=m[2][c],则x1=0,不然x1=1.当x1=0时,由m[2][c]继续构造最优解。 当x1=1时,由m[2][c]继续构造最优解。 当x1=1时,由m[2][c-w1]继续构造最优解。 依次类推,可构造出相应的最优解(x1,x2,...,xn)。 voidTraceback(int**m,intn,int*w,intc,int*x) { inti; if(m[1][c]==m[2][c]) x[1]=0; elsex[1]=1; for(i=1;i<=n-2;i++) { if(x[i]==1) c-=w[i]; if(m[i+1][c]==m[i+2][c]) x[i+1]=0; elsex[i+1]=1; } if(m[n][c]! =0) x[n]=1; } 3.动态计划 基于递归式的讨论,用二维数组m[][]来存储m(i,j)的相应值,可设计解0-1背包问题的动态计划算法Knapsack如下: template voidKnapsack(Type*v,int*w,intc,intn,Type**m) { intjMax=min(w[n]-1,c); for(intj=0;j<=jMax;j++)m[n][j]=0; for(j=w[n];j<=c;j++)m[n][j]=v[n]; for(inti=n-1;i>1;i--){ jMax=min(w[i]-1,c); for(j=0;j<=jMax;j++)m[i][j]=m[i+1][j]; for(j=w[i];j<=c;j++)m[i][j]=max(m[i+1][j],m[i+1][j-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]); } template voidTraceback(Type**m,int*w,intc,intn,int*x) { fpr(inti=1;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; } 4.回溯法求解 0-1背包问题是子集选取问题。 一般情形下,0-1背包问题是NP难的。 0-1背包问题的解空间可用子集树表示。 在搜索解空间树时,只要其左儿子结点是一个可行结点,搜索就进入其左子树。 当右子树中有可能包括最优解时才进入右子树搜索。 不然将右子树剪去。 设r是当前剩余物品价值总和;cp是当前价值;bestp是当前最优价值。 计算右子树上界的方式是将剩余物品依其单位重量价值排序,然后依次装入物品,直至装不下去时,再装入该物品的一部份而装满背包。 由此取得的价值是右子树中解的上界。 为了计算上界,可先将物品依其单位重量价值从小到大排序,尔后只要按顺序考察各物品即可。 将物品依其单位价值排序的算法如下: classObject{ friendintKnapsack(int*,int*,int,int,int*); friendvoidSort(Object*,int); public: intoperator<=(Objecta)const {return(d>=;} private: intID; floatd;n]来记录最优解,在Backtrack算法中回溯取得bestx,当取得第一个最优值,若后面回溯到叶结点时值不大于当前最优值,则最优解bestx不改变。 Backtrack中取得最优值和最优解的算法如下: template voidKnap : Backtrack(inti) { intflag; if(i>n){归求解 在编写递归的算法,最关键的就是如何用二维数组来表示相应最优解的值,编写的时候需要注意传值。 思路清楚,把数学的递归式用代码函数表示出来。 对于递归求解,算法简单,但消耗时刻太长。 在数据较少的情形下,能够专门快取得正确结果,当数据达到35个数据的时候,需要较长时刻,当数据达到40个以上的时候,由于时刻太长则等待不出结果。 可见递归的效率很低。 针对递归算法效率较低,可采用动态计划进行改良。 3.动态计划 采用动态计划算法,效率较高。 用所提供的数据测试,均能专门快得出正确结果。 在编写动态计划算法时,没有太大问题,只需要编写求出最大值和最小值的函数。 还有回溯求最优解的算法。 4.回溯法求解 在编写该算法时第一碰到的第一个问题是要运用C++的一些语法,这对于只懂C的同窗确实存在一下障碍。 好在咱们的小组成员有些人之前学过,所以在这方面问题不大,再加上不懂时通过网上查阅资料和相关书籍,问题专门快就取得解决。 另外,就是在Backtrack算法中求出最优值和最优解,每次当剩余的价值大于bestp,则进入右子树进行搜索。 当抵达叶结点时即取得一个最优值,把值赋给bestp,取得新的最优值。 同时需记录最优解,现在把记录路径的数组x[1..n]的值赋给bestx[1..n]。 在记录最优解时需要注意一个问题。 因为回溯的顺序是依照物品单位价值从高到低的顺序进行的,而输出的最优解则需要依照原顺序输出。 所以在回溯中记录路径时,需注意记录的是原来顺序下的路径,而不是排序后的路径。 在这里咱们在排序之前已经概念好一个类Q。 类中的数据成员ID用来记录物品原来的位置。 则排序后,物品原来的位置记录仍能被找到。 则搜索到某个结点时,则x[ID[i]]=1,不然x[ID[i]]=0. 5.分支界限法 分支限界法的与回溯法不同的是前者是深度优先搜索,后者是广度优先搜索。 分支限界法的效率会高些,可是需要成立一个最大堆作为优先队列。 概念一个类MaxHeap来实现优先队列,概念如下: template classMaxHeap { public: MaxHeap(Ta[],intsize,intmaxsize=50); MaxHeap(intmaxsize=50); virtual~MaxHeap(); voidInitialize(Tarrays[],intsize,intarray_size); 心算法 0 0 0 0 0 否 -- 2.递归求解 0 0 0 是 40+ 3.动态规划 0 0 0 是 -- 4.回溯法 0 0 0 0 是 -- 5.分支限界法 0 0 0 0 0 是 -- 五、附录多种算法实现清单: 带注释和功能模块说明的源程序清单: 1.贪婪算法 #include usingnamespacestd; voidsort2(intn,int*v,int*w,int*&sort) { inti,j,temp; for(i=2;i<=n;i++) { for(j=1;j<=i;j++) if(v[sort[i]]/w[i] { temp=sort[i];sort[i]=sort[j];sort[j]=temp; } } } intGreedy(intn,int*w,int*v,int*&x,intc,int*sort) { inti,value=0; for(i=n;i>=1;i--) { c-=w[sort[i]]; if(c>=0) {x[sort[i]]=1;value+=v[sort[i]];} elsebreak; } returnvalue; } intmain() { intn,c,i,value; FILE*fp; FILE*ptr; int*x,*w,*v,*sort; fp=fopen("D: \\","r");归求解 #include usingnamespacestd; intma(inti,intj,intn,int**&m,int*w,int*v) { inta,b,value; if(i==n) { if(j>=w[n]) value=v[n]; elsevalue=0; returnvalue; } if(i {if(j>=w[i]) { m[i+1][j]=ma(i+1,j,n,m,w,v); a=m[i+1][j]; m[i+1][j-w[i]]=ma(i+1,j-w[i],n,m,w,v);溯法求解 #include usingnamespacestd; template classKnap{ friendTypepKnapsack(Typep*,Typew*,Typew,int,int*); private: TypepBound(inti); voidBacktrack(inti); Typewc; { temp=Q[i-1].ID;Q[i-1].ID=Q[j-1].ID;Q[j-1].ID=temp; } } } */ template TypepKnapsack(Typepp[],Typeww[],Typewc,intn,int*x) {D=i; Q[i-1].d=*p[i]/w[i]; P+=p[i]; W+=w[i]; } if(W<=c)returnP;D]; [i]=w[Q[i-1].ID]; [i]=Q[i-1].ID; [i]=0; } =0; =0; =c; =n; =0; 支界限法 #include usingnamespacestd; #include #ifndefMAXHEAP_H #defineMAXHEAP_H template classMaxHeap { public: MaxHeap(Ta[],intsize,intmaxsize=50); MaxHeap(intmaxsize=50); virtual~MaxHeap(); voidInitialize(Tarrays[],intsize,intarray_size);< throwexception("堆空间已满"); } Data[++CurrentSize]=value; ModifyUp(CurrentSize);< throwexception("堆空"); } value=Data[1]; Data[1]=Data[CurrentSize--]; ModifyDown(1,CurrentSize);D=i; Q[i-1].d=*p[i]/w[i]; P+=p[i]; W+=w[i]; } if(W<=c)returnP;D]; [i]=w[Q[i-1].ID]; } =0; =0; =c; =n; j-1].ID]=[j]; delete[]Q; delete[]; delete[]; deltet[]; returnbestp; } intmain() { intn,c,i,value; FILE*fp; FILE*ptr; int*x,*w,*v; fp=fopen("D: \\","r"); if(! fp) { printf("filecannotbeopened"); exit (1); } fscanf(fp,"%Ld%Ld",&c,&n); x=newint[n+1]; w=newint[n+1]; v=newint[n+1]; for(i=1;i<=n;i++) { x[i]=0; fscanf(fp,"%Ld%Ld",&w[i],&v[i]); } value=Knapsack(v,w,c,n,x); //cout< /*intva=0; for(i=1;i<=n;i++) if(x[i]) va+=v[i]; cout< */ ptr=fopen("D: \\","w"); fprintf(ptr,"%d\n",value); for(i=1;i<=n;i++) fprintf(ptr,"%d%d\n",i,x[i]); fclose(fp); fclose(ptr); return0; }
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 综合 设计 实验 报告 背包 问题 多种 算法 分析