遗传算法的0-1背包问题(c语言)
数据结构与算法题解(10):0-1背包问题与部分背包问题
![数据结构与算法题解(10):0-1背包问题与部分背包问题](https://img.taocdn.com/s3/m/5512614d647d27284b7351f9.png)
假设我们有n件物品,分别编号为1, 2...n。其中编号为i的物品价值为vi ,它的重量量为wi 。为了了简
化问题,假定价值和重量量都是整数值。现在,假设我们有一一个背包,它能够承载的重量量是W。现 在,我们希望往包里里里装这些物品,使得包里里里装的物品价值最大大化,那么我们该如何来选择装的东 ⻄西呢?问题结构如下图所示:
}
public void printResult() { for(int i = 0; i < v. length; i++) { for(int j = 0; j <= weight; j++) System.out.print(c[i][j] + " "); System.out.println(); }
一一、0-1背包
1.1 初步分析
对于这个问题,一一开始确实有点不不太好入入手手。一一堆的物品,每一一个都有一一定的质量量和价值,我们
能够装入入的总重量量有限制,该怎么来装使得价值最大大呢?对于这n个物品,每个物品我们可能会 选,也可能不不选,那么我们总共就可能有2n种组合选择方方式。如果我们采用用这种办法来硬算的话,则整体的
0-1背包问题的多种解法
![0-1背包问题的多种解法](https://img.taocdn.com/s3/m/c574bed1bed5b9f3f80f1c3a.png)
问题描述0/1 背包问题 :现有 n 种物品,对 1<=i<=n ,已知第 i 种物品的重量为正整数 W i ,价值为正整数 V i , 背包能承受的最大载重量为正整数 W ,现要求找出这 n 种物品的一个子集,使得子集中物 品的总重量不超过 W 且总价值尽量大。
(注意:这里对每种物品或者全取或者一点都不取, 不允许只取一部分)算法分析根据问题描述,可以将其转化为如下的约束条件和目标函数:nw i x i W i 1 i i(1)x i { 0,1}( 1 i n)nmax v i x i (2) i1于是,问题就归结为寻找一个满足约束条件( 1 ),并使目标函数式( 2 )达到最大的 解向量 X (x 1, x 2 ,x 3, ........... , x n ) 。
首先说明一下 0-1 背包问题拥有最优解。
假设 (x 1,x 2,x 3, ........ ,x n ) 是所给的问题的一个最优解, 则(x 2,x 3, ............... ,x n )是下面问题的n n n个问 题 的 一 个 最 优解 , 则v i y iv i x i , 且 w 1x 1w i y i W 。
因此 ,i 2 i 2 i 2一个最优解:w i x i Wi2w 1x 1nmax v i x i 。
如果不是的话,设(y 2,y 3, , y n ) 是这x i {0,1}( 2 i n)i2n n nv1x1 v i y i v1x1 v i x i v i x i ,这说明(x1,y2,y3, ............. ,y n) 是所给的0-1 背包问i 2 i 2 i 1题比( x1 , x 2 , x3 , ... , x n ) 更优的解,从而与假设矛盾。
穷举法:用穷举法解决0-1 背包问题,需要考虑给定n 个物品集合的所有子集,找出所有可能的子集(总重量不超过背包重量的子集) ,计算每个子集的总重量,然后在他们中找到价值最大的子集。
遗传算法解决01背包问题
![遗传算法解决01背包问题](https://img.taocdn.com/s3/m/99e57c7c27d3240c8447efaf.png)
遗传算法解决01背包问题2015 ~2016 学年第二学期学生姓名专业学号2016年 6 月目录一:问题描述 (3)二:遗传算法原理及特点 (3)三:背包问题的遗传算法求解 (3)1.文字描述 (3)2.遗传算法中的抽象概念在背包问题的具体化 (3)3.算法求解的基本步骤 (4)四:算法实现 (4)1.数据结构 (4)2.部分代码 (5)五:结论 (8)六:参考文献 (8)一、问题描述0-1背包问题属于组合优化问题的一个例子,求解0-1背包问题的过程可以被视作在很多可行解当中求解一个最优解。
01背包问题的一般描述如下:给定n个物品和一个背包,物品i的重量为Wi,其价值为Vi,背包的容量为C。
问应如何选择合适的物品装入背包,使得背包中装入的物品的总价值最大。
注意的一点是,背包内的物品的重量之和不能大于背包的容量C。
在选择装入背包的物品时,对每种物品i只有两种选择:即装入背包或者不装入背包,不能讲物品i装入背包多次,也不能只装入部分的物品,称此类问题为0/1背包问题。
二、遗传算法原理及特点遗传算法(Genetic Algorithm)是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型,是一种通过模拟自然进化过程搜索最优解的方法。
遗传算法有着鲜明的优点:(1)遗传算法的操作对象是一组可行解,而非单个可行解;搜索轨道有多条,而非单条,因而具有良好的并行性.(2)遗传算法只需利用目标的取值信息,而无需递度等高价值信息,因而适用于任何规模,高度非线形的不连续多峰函数的优化以及无解析表达式的目标函数的优化,具有很强的通用性.(3)遗传算法择优机制是一种“软”选择,加上良好的并行性,使它具有良好的全局优化性和稳健性.(4)遗传算法操作的可行解集是经过编码化的(通常采用二进制编码),目标函数解释为编码化个体(可行解)的适应值,因而具有良好的可操作性与简单性.三、背包问题的遗传算法求解1、文字描述0-1背包问题传统的解决方法有动态规划法、分支界限法、回溯法等等。
遗传算法求解背包问题
![遗传算法求解背包问题](https://img.taocdn.com/s3/m/2191ec1db7360b4c2e3f6463.png)
遗传算法的过程:初始化:将计划装入背包的每个物品看成一个二进制串的一位,为1表示放入该物品,为0表示不放入该物品。
初始种群的产生:初始化前对放入背包物品数的一个预测(背包容积/物品最大体积),接下来只要在种群每条染色体中保证有(背包容积/物品最大体积)个为1的位初始化就完成了。
选择:选择进行杂交的父代染色体,被选中的父代染色体总是若干个染色体中最优(适应度最高)的,来保证向优化的方向发展。
详细的选择方法:随机产生2个数:Chrom_Cross_From, Chrom_Cross_To,当然得采用一定的手段来保证前者比后者小。
从Chrom_Cross_From到Chrom_Cross_To这Chrom_Cross_To-Chrom_Cross_From+1条染色体中选择最优(适应度最大)的染色体作为父代之一。
需要进行两次选择得到杂交的两条父代染色体。
这样做可以保证算法不会过早收敛。
函数实现:Individual Select(int ChromSize,Individual Pop[]){int Num_Selected,i,j,Chrom_Selected_From,Chrom_Selected_To,temp;Individual *Chrom_Selected;do{Chrom_Selected_From=rand()%PopSize;Chrom_Selected_To=rand()%PopSize;if(Chrom_Selected_From>Chrom_Selected_To){temp=Chrom_Selected_From;Chrom_Selected_From=Chrom_Selected_To;Chrom_Selected_To=temp;}Num_Selected=Chrom_Selected_To-Chrom_Selected_From+1;}while(Num_Selected<=0);Chrom_Selected=new Individual[Num_Selected];for(i=0;i<Num_Selected;i++)Chrom_Selected[i].chrom=new int[ChromSize];for(i=0,j=Chrom_Selected_From;i<Num_Selected,j<Chrom_Selected_To+1;i++,j++){Chrom_Selected[i]=Pop[j];}Order_Best_First(ChromSize,Num_Selected,Chrom_Selected);Chrom_Selected[0].fitness=Fitness(Chrom_Selected[0].chrom,ChromSize);return Chrom_Selected[0];}杂交:将两次选择得到的父代染色体进行杂交得到一条新的染色体,作为较新种群(并非新的种群)的一条染色体,杂交直到较新种群的染色体数等于原种群的染色体数。
01背包问题c语言代码回溯法
![01背包问题c语言代码回溯法](https://img.taocdn.com/s3/m/b2eb6f8459f5f61fb7360b4c2e3f5727a5e92414.png)
以下是使用C语言实现01背包问题的回溯法代码:```c#include <stdio.h>#include <stdlib.h>// 初始化背包struct knapsack {int maxWeight; // 背包最大承重int *items; // 物品数组int n; // 物品数量};// 定义物品重量、价值和数量int weights[] = {2, 2, 6, 5, 4};int values[] = {6, 3, 5, 4, 6};int quantities[] = {3, 2, 2, 1, 1};// 初始化背包最大承重和当前承重int maxWeight = 10;int currentWeight = 0;// 初始化最大价值为0int maxValue = 0;// 遍历物品数组void traverseItems(struct knapsack *knapsack, int index) { // 对于每个物品,遍历其数量for (int i = 0; i < knapsack->quantities[index]; i++) {// 如果当前物品可以放入背包装且当前承重不超过背包最大承重,计算放入该物品后的总价值,并更新最大价值if (currentWeight + weights[index] <= knapsack->maxWeight) {int currentValue = values[index] * knapsack->quantities[index];if (currentValue > maxValue) {maxValue = currentValue;}}// 回溯,将当前物品从背包装中移除,递归地尝试下一个物品knapsack->quantities[index]--;if (index < knapsack->n - 1) {traverseItems(knapsack, index + 1);}knapsack->quantities[index]++; // 恢复物品数量,以便下次遍历尝试放入其他物品}}// 主函数int main() {// 初始化背包装和物品数组struct knapsack knapsack = {maxWeight, weights, 5};knapsack.items = (int *)malloc(sizeof(int) * knapsack.n);for (int i = 0; i < knapsack.n; i++) {knapsack.items[i] = values[i] * quantities[i]; // 根据价值和数量计算物品价值,并存储在物品数组中}knapsack.n = quantities[4]; // 由于最后一个物品的数量为1,因此只需遍历前n-1个物品即可得到所有可能的结果// 使用回溯法求解01背包问题,返回最大价值traverseItems(&knapsack, 0);printf("The maximum value is %d.\n", maxValue);free(knapsack.items); // 释放内存空间return 0;}```希望以上信息能帮助到你。
c语言算法--贪婪算法---01背包问题
![c语言算法--贪婪算法---01背包问题](https://img.taocdn.com/s3/m/83474b63ddccda38376baf6d.png)
c语言算法--贪婪算法---0/1背包问题在0 / 1背包问题中,需对容量为c 的背包进行装载。
从n 个物品中选取装入背包的物品,每件物品i 的重量为wi ,价值为pi 。
对于可行的背包装载,背包中物品的总重量不能超过背包的容量,最佳装载是指所装入的物品价值最高,即n ?i=1pi xi 取得最大值。
约束条件为n ?i =1wi xi≤c 和xi?[ 0 , 1 ] ( 1≤i≤n)。
在这个表达式中,需求出xt 的值。
xi = 1表示物品i 装入背包中,xi =0 表示物品i 不装入背包。
0 / 1背包问题是一个一般化的货箱装载问题,即每个货箱所获得的价值不同。
货箱装载问题转化为背包问题的形式为:船作为背包,货箱作为可装入背包的物品。
例1-8 在杂货店比赛中你获得了第一名,奖品是一车免费杂货。
店中有n 种不同的货物。
规则规定从每种货物中最多只能拿一件,车子的容量为c,物品i 需占用wi 的空间,价值为pi 。
你的目标是使车中装载的物品价值最大。
当然,所装货物不能超过车的容量,且同一种物品不得拿走多件。
这个问题可仿照0 / 1背包问题进行建模,其中车对应于背包,货物对应于物品。
0 / 1背包问题有好几种贪婪策略,每个贪婪策略都采用多步过程来完成背包的装入。
在每一步过程中利用贪婪准则选择一个物品装入背包。
一种贪婪准则为:从剩余的物品中,选出可以装入背包的价值最大的物品,利用这种规则,价值最大的物品首先被装入(假设有足够容量),然后是下一个价值最大的物品,如此继续下去。
这种策略不能保证得到最优解。
例如,考虑n=2, w=[100,10,10], p =[20,15,15], c = 1 0 5。
当利用价值贪婪准则时,获得的解为x= [ 1 , 0 , 0 ],这种方案的总价值为2 0。
而最优解为[ 0 , 1 , 1 ],其总价值为3 0。
另一种方案是重量贪婪准则是:从剩下的物品中选择可装入背包的重量最小的物品。
0-1背包问题动态规划详解及代码
![0-1背包问题动态规划详解及代码](https://img.taocdn.com/s3/m/7d0ebd8ccc22bcd126ff0ce2.png)
0/1 背包问题动态规划详解及C代码动态规划是用空间换时间的一种方法的抽象。
其关键是发现子问题和记录其结果。
然后利用这些结果减轻运算量。
比如01背包问题。
/* 一个旅行者有一个最多能用M公斤的背包,现在有N件物品,它们的重量分别是W1,W2,...,Wn,它们的价值分别为P1,P2,...,Pn.若每种物品只有一件求旅行者能获得最大总价值。
输入格式:M,NW1,P1W2,P2......输出格式:X*/因为背包最大容量M未知。
所以,我们的程序要从1到M一个一个的试。
比如,开始任选N 件物品的一个。
看对应M的背包,能不能放进去,如果能放进去,并且还有多的空间,则,多出来的空间里能放N-1物品中的最大价值。
怎么能保证总选择是最大价值呢?看下表。
测试数据:10,33,44,55,6c[i][j]数组保存了1,2,3号物品依次选择后的最大价值.这个最大价值是怎么得来的呢?从背包容量为0开始,1号物品先试,0,1,2,的容量都不能放.所以置0,背包容量为3则里面放4.这样,这一排背包容量为4,5,6,....10的时候,最佳方案都是放4.假如1号物品放入背包.则再看2号物品.当背包容量为3的时候,最佳方案还是上一排的最价方案c为4.而背包容量为5的时候,则最佳方案为自己的重量5.背包容量为7的时候,很显然是5加上一个值了。
加谁??很显然是7-4=3的时候.上一排 c3的最佳方案是4.所以。
总的最佳方案是5+4为9.这样.一排一排推下去。
最右下放的数据就是最大的价值了。
(注意第3排的背包容量为7的时候,最佳方案不是本身的6.而是上一排的9.说明这时候3号物品没有被选.选的是1,2号物品.所以得9.)从以上最大价值的构造过程中可以看出。
f(n,m)=max{f(n-1,m), f(n-1,m-w[n])+P(n,m)}这就是书本上写的动态规划方程.这回清楚了吗?下面是实际程序(在VC 6.0环境下通过):#include<stdio.h>int c[10][100];/*对应每种情况的最大价值*/int knapsack(int m,int n){int i,j,w[10],p[10];printf("请输入每个物品的重量,价值:\n");for(i=1;i<=n;i++)scanf("%d,%d",&w[i],&p[i]);for(i=0;i<10;i++)for(j=0;j<100;j++)c[i][j]=0;/*初始化数组*/for(i=1;i<=n;i++)for(j=1;j<=m;j++){if(w[i]<=j) /*如果当前物品的容量小于背包容量*/{if(p[i]+c[i-1][j-w[i]]>c[i-1][j])/*如果本物品的价值加上背包剩下的空间能放的物品的价值*//*大于上一次选择的最佳方案则更新c[i][j]*/c[i][j]=p[i]+c[i-1][j-w[i]];elsec[i][j]=c[i-1][j];}else c[i][j]=c[i-1][j];}return(c[n][m]);}int main(){int m,n;int i,j;printf("请输入背包的承重量,物品的总个数:\n");scanf("%d,%d",&m,&n);printf("旅行者背包能装的最大总价值为%d",knapsack(m,n)); printf("\n");return 0;}。
0-1背包问题c语言实现
![0-1背包问题c语言实现](https://img.taocdn.com/s3/m/2800f3fc370cba1aa8114431b90d6c85ec3a88ca.png)
0-1背包问题c语言实现问题描述:给定n种物品和一个背包。
物品i的重量为w[i],其价值为v[i],背包的容量为c。
应如何选择装入背包的物品,使得装入背包中的物品的总价值最大。
每种物品最多装入一次。
0-1背包问题:对于要装入背包中的物品,只有两种选择:全部装入或者不装入。
背包问题:对于要装入背包中的物品,可以选择装入一部分,不一定要全部装入背包中。
算法分析:使用贪心策略求解此类问题时,首先要选出最优的度量标准。
可供选择的度量标准有三种:价值,容量,单位价值(v/w,价值/重量)。
显然,价值高的物品容量可能太大,容量大的物品价值也可能很低。
最优的度量标准是单位价值。
背包问题算法思路:1、将各个物品按照单位价值由高到低排序;2、取价值最高者放入背包;3、计算背包的剩余空间;4、重复2-3步,直到背包剩余容量=0或者物品全部装入背包为止(对于0-1背包,终止条件为背包剩余容量无法装入任意一件物品或者物品全部装入背包)。
下面是C语言实现(DEV c++4.9.9.2运行通过)[cpp]#includevoid package(int n,float c,float v[],float w[],float x[]); void package0_1(int n,float c,float v[],float w[],float x[]);int main(void){int n = 3;float c = 20;float v[] = {24,15,25};float w[] = {15,10,18};//已经按照单位价值降序排列float *x;x = (float*)malloc(sizeof(float)*n);printf("******背包*******\n");package(n,c,v,w,x);printf("*******0-1背包******\n");package0_1(n,c,v,w,x);system("PAUSE");}/** 背包问题* n:物品个数* c:背包容量* v[]:每个物品的价值* w[]:每个物品的重量(这里已经按照单位价值降序排列)* x[]:物品是否放入背包(0表示不放,1表示全部放入,0-1放入一部分)*/void package(int n,float c,float v[],float w[],float x[]){int i;for(i=0;i{x[i] = 0;//初始状态,所有物品都没有被放入背包}for(i=0;i{if(w[i] > c){break;}x[i] = 1;c = c - w[i];printf("放入第%d件物品,背包剩余容量%f.\n",(i+1),c);}if(i<=n)//还可以放入一个物品的一部分{x[i] = c/w[i];printf("放入第%d件物品的%f部分.背包剩余容量为0.\n",(i+1),w[i]*x[i]);}}/** 0-1背包问题* n:物品个数* c:背包容量* v[]:每个物品的价值* w[]:每个物品的重量(这里已经按照单位价值降序排列)* x[]:物品是否放入背包(0表示不放,1表示全部放入)*/void package0_1(int n,float c,float v[],float w[],float x[]) {int i;for(i=0;i{x[i] = 0;//初始状态,所有物品都没有被放入背包}for(i=0;i{if(w[i] > c){break;}x[i] = 1;c = c - w[i];printf("放入第%d件物品,背包剩余容量%f.\n",(i+1),c); }}#includevoid package(int n,float c,float v[],float w[],float x[]); void package0_1(int n,float c,float v[],float w[],float x[]);int main(void){int n = 3;float c = 20;float v[] = {24,15,25};float w[] = {15,10,18};//已经按照单位价值降序排列float *x;x = (float*)malloc(sizeof(float)*n);printf("******背包*******\n");package(n,c,v,w,x);printf("*******0-1背包******\n");package0_1(n,c,v,w,x);system("PAUSE");}/** 背包问题* n:物品个数* c:背包容量* v[]:每个物品的价值* w[]:每个物品的重量(这里已经按照单位价值降序排列)* x[]:物品是否放入背包(0表示不放,1表示全部放入,0-1放入一部分)*/void package(int n,float c,float v[],float w[],float x[]){int i;for(i=0;i<n;i++){x[i] = 0;//初始状态,所有物品都没有被放入背包}for(i=0;i<n;i++){if(w[i] > c){break;}x[i] = 1;c = c - w[i];printf("放入第%d件物品,背包剩余容量%f.\n",(i+1),c);}if(i<=n)//还可以放入一个物品的一部分{x[i] = c/w[i];printf("放入第%d件物品的%f部分.背包剩余容量为0.\n",(i+1),w[i]*x[i]);}}/** 0-1背包问题* n:物品个数* c:背包容量* v[]:每个物品的价值* w[]:每个物品的重量(这里已经按照单位价值降序排列)* x[]:物品是否放入背包(0表示不放,1表示全部放入)*/void package0_1(int n,float c,float v[],float w[],float x[]){int i;for(i=0;i<n;i++){x[i] = 0;//初始状态,所有物品都没有被放入背包}for(i=0;i<n;i++){if(w[i] > c){break;}x[i] = 1;c = c - w[i];printf("放入第%d件物品,背包剩余容量%f.\n",(i+1),c);}}虽然背包问题和0-1背包都具有最优子结构性质,但是背包问题用贪心算法求出来的是最优解,0-1背包问题通过贪心算法得不到最优解,因为无法保证最后能将背包装满,部分闲置的背包空间使总价值降低了。
格雷码混合遗传算法求解0-1背包问题
![格雷码混合遗传算法求解0-1背包问题](https://img.taocdn.com/s3/m/7c8ce274a26925c52cc5bf39.png)
4002 307 )
.
(. 1 南通大 学 计算机科 学与技 术学院,江 苏 南通 26 0 ;2 武汉 大学 软件工程 国家重点 实验 室, 汉 200 . 武
摘
要 :给 出 01背 包问题 的数 学模 型 , 改传 统二 进 制编码 为格 雷码 混 合遗 传 算法 , 用 贪心 算 法来 解 决约 - 修 使
近些年 , 背包 问题 吸引了很多理论和实际工作者对此问题 进行深入 的研究 。主要是 由于在工业上很多的实际应 用 , 如资
品的重量和价值分别记为 W 、 i 1 … , ) 背包能 承受 的最 p( = , n ,
大重量是 C 当物品 i , 被选择进入 背包时 , =1否则 , :0 背 , ;
m a i ie xm z
般仅能获得 问题 的近似最优解 。近年来 , 不少学者将稳健 的
s 3 a t l ≤c uj to∑ x ] c i
中图分类 号 :T 1 P8 文献标 志码 :A 文章 编号 :10 -6 5 2 1 ) 8 2 0 - 3 0 13 9 ( 0 2 0 -9 6 0
d i1 . 9 9 ji n 10 -6 5 2 1 . 8 0 7 o :0 3 6 / .s . 0 139 . 0 2 0 .2 s
v re e rc s. en e g n e p o e s Th ume c le p rm e o e h fe t iy o h lo t m . i r a x e i ntprv s te a ci t ft e ag r h v i
K yw r s eei a o tm( A) npakpolm;G r cd ;ged grh e od :gnt l rh G ;ka sc rbe c gi a oe reya o tm;eis c ai y l i li mehns tm m
0-1背包问题(回溯法)
![0-1背包问题(回溯法)](https://img.taocdn.com/s3/m/0c20fa6658fafab069dc0243.png)
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背包问题,明显比动态规划法更优良。
遗传算法求解01背包问题
![遗传算法求解01背包问题](https://img.taocdn.com/s3/m/dd82dca8680203d8ce2f2483.png)
遗传算法求解01背包问题一、问题描述01背包问题属于组合优化问题的一个例子,求解01背包问题的过程可以被视作在很多可行解当中求解一个最优解。
01背包问题的一般描述如下:给定n个物品和一个背包,物品i的重量为W i,其价值为V i,背包的容量为C。
选择合适的物品装入背包,使得背包中装入的物品的总价值最大。
注意的一点是,背包内的物品的重量之和不能大于背包的容量C。
在选择装入背包的物品时,对每种物品i只有两种选择:装入背包或者不装入背包,即只能将物品i装入背包一次。
称此类问题为0/1背包问题。
01背包问题是NP问题,传统的解决方法有动态规划法、分支界限法、回溯法等等。
传统的方法不能有效地解决01背包问题。
遗传算法(Genetic Algorithms)则是一种适合于在大量的可行解中搜索最优(或次优)解的有效算法。
二、遗传算法1、遗传算法的基本思想遗传算法的搜索从一个被称作种群的候选解集开始,新的种群由旧的种群中产生以期得到更好的种群。
从旧种群中按照解的适应度来选择解以产生新的解;适应度越大,解被选择生成后代的机率也越大。
这个从已有种群中选择双亲并产生后代的迭代过程持续到遗传算法的停止条件满足为止。
2、遗传算法的基本元素。
遗传算法由以下几个原素组成:由染色体组成的种群,根据适应度进行选择以及交叉产生后代。
三、用遗传算法求解01背包问题1、01背包问题中染色体的表示。
用向量X来表示染色体,X = {x1,x2,……,x n}。
,x i∈{0,1},x i=1表示物品i装入了背包,x i =0表示物品i未装入背包。
每个染色体对应其当前装入背包的物品的总价值和总重量。
背包中物品的中价值代表了该物品的适应度。
程序中定义了这样的一个结构来表示染色体:typedef struct{int Weight; //染色体代表的物品的总重量int Fitness; //染色体代表的物品的价值(适应度)int Gene[NUMG]; //用元素取值于定义域{0,1}的数组表示染色体。
分支限界法 01背包问题c语言
![分支限界法 01背包问题c语言](https://img.taocdn.com/s3/m/82c383c3ed3a87c24028915f804d2b160a4e8644.png)
分支限界法 01背包问题c语言分支限界法是一种解决组合优化问题的算法。
其中,01背包问题是一种经典的背包问题,它要求在给定的容量下,选择商品的组合,使得组合的总价值达到最大化,但组合中每种商品只能选择一次。
C语言是一种广泛使用的编程语言,适用于实现各种算法和数据结构。
下面我将用C语言实现分支限界法来解决01背包问题。
首先,我们定义一个结构体用来表示商品的信息,包括商品的重量和价值:```typedef struct {int weight;int value;} Item;```接下来,我们定义一个递归函数来实现分支限界法。
该函数通过深度优先搜索的方式,尝试不同的选择,并计算当前组合的总价值。
如果当前组合的总价值已经超过了已知的最优解,则剪枝,不再继续搜索。
```void branchAndBound(int index, int capacity, int currentWeight, int currentValue, int n, Item items[], int bestValue, int choice[]) {if (index >= n || currentWeight >= capacity) {if (currentValue > bestValue) {bestValue = currentValue;// 更新最优解for (int i = 0; i < n; i++) {choice[i] = tempChoice[i];}}return;}// 选择当前商品if (currentWeight + items[index].weight <= capacity) {currentWeight += items[index].weight;currentValue += items[index].value;tempChoice[index] = 1;branchAndBound(index + 1, capacity, currentWeight, currentValue, n, items, bestValue, choice);currentWeight -= items[index].weight;currentValue -= items[index].value;tempChoice[index] = 0;}// 不选择当前商品branchAndBound(index + 1, capacity, currentWeight, currentValue, n, items, bestValue, choice);}最后,我们可以在主函数中调用分支限界法来解决01背包问题。
01背包问题回溯法c语言
![01背包问题回溯法c语言](https://img.taocdn.com/s3/m/ced70927ae1ffc4ffe4733687e21af45b207fe6a.png)
01背包问题回溯法c语言背包问题是一个很经典的动态规划问题,其中最常见的一种形式就是 01 背包问题。
在该问题中,给定一组物品的重量和价值,以及一个背包的容量限制,要求选择一些物品,使得在不超过背包容量的前提下,背包中物品的总价值最大。
这里我们将讨论如何使用回溯法解决01 背包问题,使用C 语言进行编程实现。
首先,我们需要定义问题的数据结构。
我们可以使用一个数组来表示不同物品的重量和价值,背包的容量可以通过一个常量来表示。
```c#define N 5 // 物品的个数#define MAX_WEIGHT 10 // 背包的容量int weights[N] = {2, 3, 4, 5, 9}; // 物品的重量int values[N] = {3, 4, 5, 8, 10}; // 物品的价值int bestValue = 0; // 最优解的价值int bestSelection[N]; // 最优解中物品的选择情况```接下来,我们可以定义一个递归函数来实现回溯法。
该函数将遍历所有可能的物品选择情况,并更新当前的最优解。
```cvoid backtrack(int depth, int weight, int value, int selection[]) {if (depth == N) {if (weight <= MAX_WEIGHT && value > bestValue) {bestValue = value;for (int i = 0; i < N; i++) {bestSelection[i] = selection[i];}}return;}// 不选择当前物品selection[depth] = 0;backtrack(depth + 1, weight, value, selection);// 选择当前物品selection[depth] = 1;backtrack(depth + 1, weight + weights[depth], value + values[depth], selection); }```最后,我们可以在主函数中调用回溯函数,得到最优解。
0-1背包问题(分支限界法)
![0-1背包问题(分支限界法)](https://img.taocdn.com/s3/m/1afe4a8979563c1ec5da71cc.png)
分支限界法——01背包问题12软工028 胡梦颖一、问题描述0-1背包问题:给定n种物品和一个背包。
物品i的重量是Wi,其价值为Vi,背包的容量为C。
应如何选择装入背包的物品,使得装入背包中物品的总价值最大?在选择装入背包的物品时,对每种物品i只有2种选择,即装入背包或不装入背包。
不能将物品i装入背包多次,也不能只装入部分的物品i。
二、问题分析分支限界法类似于回溯法,也是在问题的解空间上搜索问题解的算法。
一般情况下,分支限界法与回溯法的求解目标不同。
回溯法的求解目标是找出解空间中满足约束条件的所有解,而分支限界法的求解目标则是找出满足约束条件的一个解,或是在满足约束条件的解中找出使某一目标函数值达到极大或极小的解,即在某种意义下的最优解。
由于求解目标不同,导致分支限界法与回溯法对解空间的搜索方式也不相同。
回溯法以深度优先的方式搜索解空间,而分支限界法则以广度优先或以最小耗费优先的方式搜索解空间。
分支限界法的搜索策略是,在扩展结点处,先生成其所有的儿子结点(分支),然后再从当前的活结点表中选择下一扩展结点。
为了有效地选择下一扩展结点,加速搜索的进程,在每一个活结点处,计算一个函数值(限界),并根据函数值,从当前活结点表中选择一个最有利的结点作为扩展结点,使搜索朝着解空间上有最优解的分支推进,以便尽快地找出一个最优解。
这种方式称为分支限界法。
人们已经用分支限界法解决了大量离散最优化的问题。
三.源代码#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("物品%d:重量:%.1f,价值:%.1f\n",k,w[k],v[k]);}printf("最大价值为:%.1f\n",bestv);}void main(){int c;float ewv[MaxSize];printf("请输入背包的最大容量v:");scanf("%d",&c);printf("请输入物品总数n:");scanf("%d",&n);printf("请输入物品的重量和单位重量价值:\n");for(int i=1;i<=n;i++){printf("第%d件物品:",i);scanf("%f%f",&w[i],&ewv[i]);v[i]=w[i]*ewv[i];}maxLoading(w,v,c);}五.实验结果。
“遗传算法”解决“背包问题”
![“遗传算法”解决“背包问题”](https://img.taocdn.com/s3/m/e4662b7730b765ce0508763231126edb6f1a76d7.png)
“遗传算法”解决“背包问题”遗传算法基本思想:1) ⼀个种群有多个个体,每个个体有染⾊体和对应的基因为了繁殖进⾏:2) 选择:在残酷的世界中,适者⽣存,优胜略汰。
3) 重组:染⾊体交叉,基因重组4) 突变:染⾊体上的基因⼩概率的突变(⼀般给⼩数点后两位)背包问题:背包只能容得下⼀定重量b的物品,物品有m种,每种物品有⾃⼰的重量w(i)和价值v(i)(0<i<=m),从这些物品中选择装⼊背包,是背包不超过重量b,但价值⼜要最⼤。
运⽤动态规划,分⽀限界都可以达到效果,但不佳。
我⽤遗传算法解决:⼀般⼈有多条染⾊体,但对于背包问题,⼀个解我们将看成⼀个个体,所以,⼀个个体只有⼀个染⾊体,⼀个染⾊体对应多个基因。
如:100101010100111 表⽰装⼊背包的可能解。
(具体情况具体分析)遗传所做准备:1) ⽤0表⽰“不选择装⼊”,1表⽰“装⼊”,形成⼀条基因链;100101010100111则表⽰“15种物品”装⼊或不装⼊背包的可能解。
------- 此处⽤chrom[]存放基因,代表染⾊体2) ⼀个基因对应⼀个个体。
------- 此处⽤Population类或结构体声明其含有chrom[]等信息3) 可能的解有很多,构成⼀个种群。
------- ⽤Population类定义⼀个数组代表个体构成的种群newPop[]:存放新⽣代,oldPop[]:存放上⼀代4) 适应度:适应度和⽬标函数是正相关的,所以需要物品价值和重量。
------- fitness,weight包含在Population类中最⼤适应度:maxFitness,最⼩适应度:minFitness,总适应度:sumFitness,(帮助求突变和交叉的染⾊体)平均适应度:avgFitness遗传算法的函数:基本:1) InitPop() 初始化个体,使每个个体都有基因组2) Statistics(*pop) 计算适应度(最⼤,最⼩,总的,平均的)3) Selection(*pop) 通过选择种群中符合要求的⽗母去繁殖新代,返回这对⽗母的位置4) crossover(*parent1,*parent2,pos) 传⼊要改的个体位置,随机产⽣交叉位置,⽤优良⽗母繁殖优良后代并替代传⼊个体位置5) mutation(i) i为基因组基因的位置,逐个基因看是否要变异6) generation() 对个体进⾏判断,若不符合要求,进⾏选择,重组,突变。
01背包问题及变种详解
![01背包问题及变种详解](https://img.taocdn.com/s3/m/99bc922ce2bd960590c67757.png)
P01: 01背包问题题目有N件物品和一个容量为V的背包。
第i件物品的费用是c[i],价值是w[i]。
求解将哪些物品装入背包可使价值总和最大。
基本思路这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放。
用子问题定义状态:即f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。
则其状态转移方程便是:f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}这个方程非常重要,基本上所有跟背包相关的问题的方程都是由它衍生出来的。
所以有必要将它详细解释一下:“将前i件物品放入容量为v的背包中”这个子问题,若只考虑第i件物品的策略(放或不放),那么就可以转化为一个只牵扯前i-1件物品的问题。
如果不放第i件物品,那么问题就转化为“前i-1件物品放入容量为v的背包中”,价值为f[i-1][v];如果放第i件物品,那么问题就转化为“前i-1件物品放入剩下的容量为v-c[i]的背包中”,此时能获得的最大价值就是f[i-1][v-c[i]]再加上通过放入第i件物品获得的价值w[i]。
优化空间复杂度以上方法的时间和空间复杂度均为O(VN),其中时间复杂度应该已经不能再优化了,但空间复杂度却可以优化到O。
先考虑上面讲的基本思路如何实现,肯定是有一个主循环i=1..N,每次算出来二维数组f[i][0..V]的所有值。
那么,如果只用一个数组f[0..V],能不能保证第i次循环结束后f[v]中表示的就是我们定义的状态f[i][v]呢?f[i][v]是由f[i-1][v]和f[i-1][v-c[i]]两个子问题递推而来,能否保证在推f[i][v]时(也即在第i次主循环中推f[v]时)能够得到f[i-1][v]和f[i-1][v-c[i]]的值呢?事实上,这要求在每次主循环中我们以v=V..0的顺序推f[v],这样才能保证推f[v]时f[v-c[i]]保存的是状态f[i-1][v-c[i]]的值。
求解0/1背包问题的快速收敛的混合遗传算法
![求解0/1背包问题的快速收敛的混合遗传算法](https://img.taocdn.com/s3/m/2ddf11213169a4517723a38f.png)
r p a e t e s lc in o e ao a e n se d - tt e r d c in s a e y t e c n e g n p e f t e n w ag rt m a e l c d wi a n w e e t p r tr b s d o t a y sae r p o u t t t g ,h o v r e t s e d o h e lo h c n h o o r i
E- i: o g p n @1 3c m mal d n _ e g 6 .o
DONG e g Hy rd g n t l o ih wiI h g o v r e ts e d f r s l i g 0 1 k a a k p o lm . mp t r En i e rn P n . b i e e i a g r t m t i h c n e g n p e o o v n / n ps c r b e Co c l u e gn e ig
S h o fT af a d T a s ott n E gn e n L n h u Ja tn iest, a z o 3 0 0, hn c o lo rfc n rn p rai n ie r g, a z o ioo g Unv ri L n h u 7 0 7 C ia i o i y
DO :037 /i n1 0 — 3 1 0 8 0 1 文章编 号 :0 2 8 3 ( 0 8 3 — 0 7 0 文献 标识码: 中图分类号: P 0 . I 1 . 8 .s. 2 8 3 . 0 . . 4 7 js 0 2 30 10 — 3 12 0 )0 0 4 — 3 A T 31 6
摘
要: 在结合贪婪 算法的混合遗传算 法 中, 将基 于轮盘赌 的选择 算子 改为稳 态复制的选择 算子 , 形成 的新 的混合遗传 算法能显
0-1背包问题的遗传算法求解及其改进
![0-1背包问题的遗传算法求解及其改进](https://img.taocdn.com/s3/m/ace2c701f78a6529647d5321.png)
规 划,回溯 法等.本文探讨 了一种基 于贪心算法 的混合遗传算法求解01 包问题的方法 ,并在 实验 中获得 了更 .背
佳近似解.
关键词:O1 . 背包问题:贪. 算法;遗传算法
中图分类号 :0 4 25 文献标识码:A 文章编号 :17 6 2— 0 2 2 1 )0 5 0(0 0 2一 o l o 3一 O 3
0 引 言
近年 来,背包 问题吸 引了许多理论研究人员和实 际工 作者对此 问题 做深入的研究 ,在理 论上尽管 该问题 结构简 单 ,但 它却具有 组合爆炸 的性质 ,在实 际应用 中,许 多工业 问题可 以用背包 问题来 描述 ,如 资本 预
算、货物装载 、资源分配和存 储分配等都是典型 的应用例子 .所 谓背包 问题 ,是 指从n件 不同价值 ,不 同 重
好 的效 果:启发式算法包括贪心算法 ,遗传算法等 ,一般 用于求解更为复杂的 问题 .解 决背包 问题的关键 在
于约束 条件 的处理 . 目前一般采用 惩罚函数 的方法 处理约束条件 ,该方法 当问题规模较大 时,尽管可行 ,但 搜索效率很低 ,有时甚至得到的结果 比一般 的启发 式算法还要 差.因此 ,本文提 出了一种基 于贪心算法 的混
的搜索空问.
② 遗传算法在选择 、交叉和变 异的过程 中,都存在对每 一个体进行处理 的可 能.若遗传算 法每一代对群
体规模为 的个体进行操作,实际上处理了大约D( 1 个模式,具有很高的并行性,因而具有显著 的搜索效率. ③ 遗传算法对于各种特殊 问题可 以提供 极大 的灵活性来混合构造领域独立 的启发 式,从 而保证算法 的有
④ 选择操 作.根据某种算法从种群中挑选个体作为遗传操作的父个体 ; ⑤ 交叉操 作.按一定的概率对父个体实施 交叉操作产生新一代子个体;
分支界线法01背包问题c语言
![分支界线法01背包问题c语言](https://img.taocdn.com/s3/m/9d388a22793e0912a21614791711cc7931b77806.png)
分支界线法01背包问题c语言一、问题描述01背包问题是常见的动态规划问题,其描述如下:有一个背包,最多能承载重量为W的物品。
现在有n个物品,其重量分别为w1, w2, ..., wn,价值分别为v1, v2, ..., vn。
要求选取若干物品放入背包,使得放入背包的物品总价值最大,且总重量不超过W。
二、分支界线法思想分支界线法是一种求解组合优化问题的常用方法。
在01背包问题中,分支界线法的思想是通过一个优先级队列,不断生成和扩展状态空间树,记录每个节点的上界评价函数值,并根据上界值进行搜索剪枝,直至获得最优解。
三、算法步骤1. 定义物品结构体```ctypedef struct {double value; // 物品价值double weight; // 物品重量double unitValue; // 物品单位价值} Item;```2. 比较函数定义(用于优先级队列)```cintpare(const void* a, const void* b) {Item* itemA = (Item*)a;Item* itemB = (Item*)b;double diff = itemB->unitValue - itemA->unitValue; return diff < 0 ? -1 : diff > 0 ? 1 : 0;}```3. 分支界线法求解01背包问题```cdouble knapsack(int n, double W, Item* items) {qsort(items, n, sizeof(Item),pare);double maxValue = 0;double currentWeight = 0;for (int i = 0; i < n; i++) {if (currentWeight + items[i].weight <= W) {currentWeight += items[i].weight;maxValue += items[i].value;} else {double rem本人nWeight = W - currentWeight;maxValue += items[i].unitValue * rem本人nWeight;break;}}return maxValue;}```四、代码实现解释1. 首先根据物品单位价值对物品进行排序,通过单位价值可以快速确定选择哪个物品放入背包;2. 依次选择单位价值最高的物品放入背包,若背包容量不足则按部分放入;3. 根据剩余容量,估算能够放入的最大价值。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
基于遗传算法的0-1背包问题的求解摘要:一、前言组合优化问题的求解方法研究已经成为了当前众多科学关注的焦点,这不仅在于其内在的复杂性有着重要的理论价值,同时也在于它们能在现实生活中广泛的应用。
比如资源分配、投资决策、装载设计、公交车调度等一系列的问题都可以归结到组合优化问题中来。
但是,往往由于问题的计算量远远超出了计算机在有效时间内的计算能力,使问题的求解变为异常的困难。
尤其对于NP 完全问题,如何求解其最优解或是近似最优解便成为科学的焦点之一。
遗传算法已经成为组合优化问题的近似最优解的一把钥匙。
它是一种模拟生物进化过程的计算模型,作为一种新的全局优化搜索算法,它以其简单、鲁棒性强、适应并行处理以及应用范围广等特点,奠定了作为21世纪关键智能计算的地位。
背包问题是一个典型的组合优化问题,在计算理论中属于NP-完全问题, 其计算复杂度为)2(O n ,传统上采用动态规划来求解。
设w[i]是经营活动 i 所需要的资源消耗,M 是所能提供的资源总量,p[i]是人们经营活动i 得到的利润或收益,则背包问题就是在资源有限的条件下, 追求总的最大收益的资源有效分配问题。
二、问题描述背包问题( Knapsack Problem)的一般提法是:已知n 个物品的重量(weight )及其价值(或收益profit )分别为0>i w 和0>i p ,背包的容量(contain )假设设为0>i c ,如何选择哪些物品装入背包可以使得在背包的容量约束限制之内所装物品的价值最大?该问题的模型可以表示为下述0/1整数规划模型:目标函数:∑==ni i i n x c x x x f 121),,(max⎪⎩⎪⎨⎧=∈≤∑=),2,1(}1,0{t .s 1n i x p x w i n i i i i (*)式中i x 为0-1决策变量,1=i x 时表示将物品i 装入背包中,0=i x 时则表示不将其装入背包中。
三、求解背包问题的一般方法解决背包问题一般是采取动态规划、递归回溯法和贪心方法。
动态规划可以把困难得多阶段决策变换为一系列相互联系比较容易的单阶段问题。
对于背包问题可以对子过程用枚举法求解,而且约束条件越多,决策的搜索范围越小,求解也越容易。
它的主要缺点是用数值方法求解时会随着状态变量的个数呈指数级的增长,往往对于求解背包问题的实际问题是不现实的。
使用递归回溯法解决背包问题的优点在于它算法思想简单, 而且它能完全遍历搜索空间,肯定能找到问题的最优解;但是由于此问题解的总组合数有n 2个,因此,随着物件数 n 的增大,其解的空间将以n2级增长,当 n 大到一定程度上,用此算法解决背包问题将是不现实的。
使用贪心方法求解时计算的复杂度降低了很多,但是往往难以得到最优解,有时所得解与最优解相差甚远。
因此, 我们可以探索使用遗传算法解决物件数较大的背包问题。
四、遗传算法简介遗传算法( Genetic Algorithms ,GA) 是在1975 年首次由美国密西根大学的D 。
J 。
Holland 教授和他的同事们借鉴生物界达尔文的自然选择法则和孟德尔的遗传进化机制基础之上提出的。
经过近30年的研究、应用,遗传算法已被广泛地应用于函数优化、机器人系统、神经网络学习过程、模式识别、图象处理、工业优化控制等领域。
遗传算法是将问题的每一个可能性解看作是群体中的一个个体(染色体),并将每一个染色体编码成串的形式,再根据预定的目标函数对每个个体进行评价,给出一个适应值。
算法将根据适应度值进行它的寻优过程,遗传算法的寻优过程是通过选择、杂交和变异三个遗传算子来具体实现的。
它的搜索能力由选择算子和杂交算子决定,变异算子则保证了算法能够搜索到问题空间的尽可能多的点,从而使其具有搜索全局最优的能力。
遗传算法的高效性和强壮性可由Holland 提出的模式定理( Schema Therem) 和隐式并行性得以解释。
在遗传算法中,定义长度较短、低阶且适应值超过平均适应值的模式在群体中数目的期望值按指数递增,这个结论称为遗传算法的基本定理。
遗传算法是通过定义长度短、确定位数少、适应度值高的模式的反复抽样、组合来寻找最佳点,称这些使遗传算法有效工作的模式为积木块,是遗传算法构造答案的基本材料。
但归根到底,要使遗传算法有效工作必须按照遗传算法的模式定理(或积木块假设) 根据具体问题设计合理的编码方案。
在运行遗传算法程序时,需要对一些参数作事先选择,它们包括种群的大小、染色体长、交叉率、变异率、最大进化代数等,这些参数对GA 的性能都有很重p= 0.4 要的影响。
在试验中参数一般选取如下:种群大小N= 20~100 ,交叉概率c~0.9 ,变异概率p= 0.001~0.1 ,最大进化代数maxgen = 100~500。
m遗传算法是具有“生成+检测”的迭代过程的搜索算法。
它的基本处理流程如图1所示。
遗传算法的基本流程描述如下:(1)编码:将解空间的解数据进行二进制编码,表达为遗传空间的基因型串(即染色体)结构数据,如将数据9编码为“1001”;(2)初始化种群:定义整数pop_size 作为染色体的个数,并且随机产生pop_size个染色体作为初始种群;(3)评估种群中个体适应度:评价函数对种群中的每个染色体(chromosome )求得其个体适应度)(fitness f i ;(4)选择:选择把当前群体中适应度较高的个体按某种规则或者模型遗传到下一代种群中,这里所用的规则是:染色体在种群中被选择的可能性与其个体的适应度的大小成正比;(5)交叉:定义参数c p 作为交叉操作的概率,由(4)选择得到的两个个体以概率c p 交换各自的部分染色体,得到新的两个个体;(6)变异:定义参数m p 作为变异操作的概率,由(5)得到每个个体中的每个基因值都以概率m p 进行变异;(7)演化:经过选择、交叉和变异操作,得到一个新的种群,对上述步骤经过给定的循环次数(maxgen )的种群演化,遗传算法终止。
五、背包问题的遗传算法求解描述基于背包问题的模型(*),我们设计了针对于背包问题的染色体编码方法:将待求解的各量X 表示成长为n 的二进制字符串]j [x ,j=1,2, …,n 。
0]j [x =表示物体j 不放入背包内,1]j [x =表示物体j 放入背包内。
例如:111001100…000111代表一个解,它表示将第1、2、3、6、7…n-2,n-1,n 号物体放入背包中,其它的物体则不放入。
根据遗传算法的基本流程,我们确定了求解背包问题的遗传算法:步骤1、初始化过程1.1 确定种群规模popsize 、杂交概率c p 、变异概率m p 、染色体长度lchrom 及最大进化代数maxgen ;1.2 读入背包问题的相关信息,如每个物体的重量weight[j]、每个物体的收益profit[j]和背包的容量contain ,其中1)lchrom (,1,0j -= ; 1.3 取1)lchrom (,1,0j )1,0(u ]j [x -== ,其中)1,0(u 表示0-1整数的均匀分布函数,即随机地生成数0或1,生成的]j [x 串即可看为一个染色体个体。
若不满足模型(*)的约束条件,则拒绝接受,由1.2重新生成一个新的染色体个体chrom ;如果产生的染色体可行,则接受它作为种群的一名成员,经过有限次的1.2抽样后,得到popsize 个可行的染色体chrom ,形成新的种群。
1.4 置种群的代数gen=0;步骤2、计算种群中个体适应度以及统计种群适应度情况2.1 按照下列公式计算种群中个体适应度:)1(1lchrom 0j ]j [chrom *]j [weight weight ∑-==;)2(containifweight )contain weight (*alpha ]j [chrom *]j [profit contain ifweight ]j [chrom *]j [profit fitness 1lchrom 0j 1lchrom 0j ⎪⎪⎩⎪⎪⎨⎧>--≤=∑∑-=-= 公式(2)的下半部分即为适应度的惩罚函数,其中参数 1.0alpha >。
2.2 按公式(3)计算种群的总体适应度,)3(]i [fitness sumfitness 1popsize 0i ∑-==并且按照排序的方法统计出种群中的最大、最小适应度的染色体个体,分别标记为maxpop 、minpop ;步骤3、选择操作3.1 生成一个随机数rand_Number ,要求1_0<<Nuber rand ;3.2 按照赌轮法选择个体,赌轮法的算法描述如下:int selection( ){i=0; //个体的编号sum=0; //部分个体适应度的累加和//根据随机数和群体的总适应度确定赌轮的位置wheel-pos=rand_Number*sufitness;while sum<wheel-pos && i<=popsize{ i=i+1;sum=sum+fitness[i]; //fitness 为第i 个个体的适应度}return i-1; //选择了个体i-1}3.3 重复两次操作3.1、3.2,生成两个个体作为交叉操作的父代;步骤四、交叉操作4.1 根据事先定义好的交叉概率c p ,为了确定是否进行交叉操作,则生成[0,1]的随机数pp ,若c p pp <,则进行4.2交叉操作,否则将两个父代保留为下一代的两个个体;4.2 随机生成]1lchrom ,[0-的整数作为交叉点,对两个父代个体交叉生成新的两个个体;4.3 重复pop_size/2次4.1、4.2便可生成pop_size 个个体组成新的种群; 步骤五、 变异操作5.1 根据事先定义好的变异概率m p ,为了确定新种群上的每个个体上的每个基因是否进行变异操作,则生成[0,1]的随机数pp ,若m p pp <,则进行5.2变异操作,否则基因不变异;5.2 基因变异操作为原基因若为1,则新基因则变异为0,若原基因为0,则新基因变异为0;步骤6、 演化6.1 按步骤2的方法计算新种群的个体适应度和总体适应度情况,尤其是找出新种群中最大适应度的个体和最小适应度的个体;6.2 若旧种群的最大个体适应度〉新种群的最大个体适应度,把旧种群的最大适应度的个体代替新种群中的最小适应度的个体,否则进行6.3;6.3 种群的代数gen=genm+1,若gen 〉Maxgen ,则结束种群的演化,否则转到步骤2。
六、遗传算法求解的实现1、遗传算法的主要参数#define popsize 80 //种群的规模#define pc 0.7 //杂交概率#define pm 0.1 //变异概率#define lchrom 50 //染色体长度#define maxgen 5000 //最大进化代数double alpha; //计算适应度时使用的惩罚函数系数2、数据结构(1)背包信息://背包问题中物体重量、收益、背包容量int weight[lchrom],profit[lchrom],contain;(2)种群个体结构体struct population{unsigned int chrom[lchrom]; //染色体double fitness; //适应度unsigned int parent1,parent2,cross; //双亲、交叉点};(3)父代种群和新生代种群//父代种群、新生代种群struct population oldpop[popsize],newpop[popsize]; //pop_size为种群大小(4)适应度信息//种群的总适应度、最小、最大适应度double sumfitness,minfitness,maxfitness;//一个种群中最大和最小适应度的个体编号int minpop,maxpop;3、主要函数说明(1)、int read_infor( )功能:从文件knapsack.txt中读出背包信息(物体重量、收益、背包容量);参数:无;返回值:返回读取文件信息是否正确;流程图:见图2。