java遗传算法解决背包问题,遗传算法算法实现背包问题

一、

问题描述

背包问题(Knapsack

problem)是一种组合优化的NP完全问题。问题可以描述为:给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,我们如何选择,才能使得物品的总价格最高。问题的名称来源于如何选择最合适的物品放置于给定背包中。相似问题经常出现在商业、组合数学,计算复杂性理论、密码学和应用数学等领域中。也可以将背包问题描述为决定性问题,即在总重量不超过W的前提下,总价值是否能达到V?它是在1978年由Merkel和Hellman提出的。

二、

知识表示

1、遗传算法

遗传算法(Genetic

Algorithm)是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型,是一种通过模拟自然进化过程搜索最优解的方法,它最初由美国Michigan大学J.Holland教授于1975年首先提出来的,并出版了颇有影响的专著《Adaptation in Natural and Artificial

Systems》,GA这个名称才逐渐为人所知,J.Holland教授所提出的GA通常为简单遗传算法(SGA)。

遗传算法是从代表问题可能潜在的解集的一个种群(population)开始的,而一个种群则由经过基因(gene)编码的一定数目的个体(individual)组成。每个个体实际上是染色体(chromosome)带有特征的实体。染色体作为遗传物质的主要载体,即多个基因的集合,其内部表现(即基因型)是某种基因组合,它决定了个体的形状的外部表现,如黑头发的特征是由染色体中控制这一特征的某种基因组合决定的。因此,在一开始需要实现从表现型到基因型的映射即编码工作。由于仿照基因编码的工作很复杂,我们往往进行简化,如二进制编码,初代种群产生之后,按照适者生存和优胜劣汰的原理,逐代(generation)演化产生出越来越好的近似解,在每一代,根据问题域中个体的适应度(fitness)大小选择(selection)个体,并借助于自然遗传学的遗传算子(genetic operators)进行组合交叉(crossover)和变异(mutation),产生出代表新的解集的种群。这个过程将导致种群像自然进化一样的后生代种群比前代更加适应于环境,末代种群中的最优个体经过解码(decoding),可以作为问题近似最优解。

2、状态空间

所谓状态,

是指在一定的时空范围内,问题所涉及的人、物、时间等的布局关系。通常把问题的初始布局关系称为初始状态,问题解决时到达的状态叫目标状态。这两个状态之间存在差异,如何从初始状态到达目标状态就是对问题求解。在状态空间法中问题的求解通常是从初始状态到达目标状态的一条最佳路径,这条路径依靠搜索算法在状态空间中寻找,这就是状态空间法的核心所在。

在背包问题中,初始状态就是有一个空包,包的重量固定为W,有N个商品,每个商品的重量为Wi,价值Ci。目标状态就是将n(n<=N)个商品装入包里,包重不超过W,使得包中商品的总重量最大。状态空间就是将商品装入包的所有组合,本实验的解就是价值和最大的装包组合。

3、遗传算法中的抽象概念在背包问题的具体化

(1)基因:0或1,代表相应的商品选还是不选。

(2)染色体:本实验中固定有50个商品,所以染色体就是50个基因序列,也就是40个0、1串,代表了一种往包里装商品的组合。一个染色体例:0111101101011011110101110101010101011110。

(3)群体:一定数量的基因个体组成了群体(population),群体中个体的数量叫做群体大小。本实验的背包问题中,种群大小为100,代表100个往包里装商品的组合。

(4)适应度:各个个体对环境的适应程度叫做适应度。本实验的背包问题中,每染色体个体的适应度为选入包中的商品的价值和。

三、

算法实现

1、

数据结构

(1)

重要参数:

#define zhongqun_size 100

//种群的规模

#define pc 0.8

//杂交概率

#define pm 0.08

//变异概率

#define chrom_length 50

//染色体长度

#define max_daishu 1000

//最大进化代数

(2)

染色个体:

struct population

{

unsigned int chrom[chrom_length];

//染色体

double weight;

//背包重量

double fitness;

//适应度

unsigned int parent1,parent2,cross; //双亲、交叉点

};

(3)

种群:

//新生代种群、父代种群

struct population

oldpop[zhongqun_size],newpop[zhongqun_size];

2、

程序流程

(1)读取存取包的限种、商品的重要和价值的TXT文件;

(2)初始化种群;

(3)计算群体上每个个体的适应度值(Fitness) ;

(4)评估适应度,对当前群体P(t)中每个个体Pi计算其适应度F(Pi),适应度表示了该个体的性能好坏;

(5)依照Pc选择个体进行交叉操作 ;

(6)仿照Pm对繁殖个体进行变异操作

(7)没有满足某种停止条件,则转第3步,否则进入8

(8)输出种群中适应度值最优的个体。

四、

实验结果分析

a4c26d1e5885305701be709a3d33442f.png

通过多次测试,工程实现遗传算法的背包问题,能够生成较优的装包组合。

五、

程序清单

#include "stdafx.h"

#include

#include

// 重要常量参数

#define zhongqun_size 100

//种群的规模

#define pc 0.8

//杂交概率

#define pm 0.08

//变异概率

#define chrom_length 50

//染色体长度

#define max_daishu 1000

//最大进化代数

struct population

{

unsigned int chrom[chrom_length];

//染色体

double weight;

//背包重量

double fitness;

//适应度

unsigned int parent1,parent2,cross; //双亲、交叉点

};

//新生代种群、父代种群

struct population

oldpop[zhongqun_size],newpop[zhongqun_size];

//背包问题中物体重量、收益、背包容量

int

weight[chrom_length],profit[chrom_length],bagweight;

//种群的总适应度、最小、最大、平均适应度

double

sumfitness,minfitness,maxfitness,avgfitness;

//计算适应度时使用的

惩罚函数系数

double alpha;

//一个种群中最大和最小适应度的个体

int

minpop,maxpop;

void

read_infor()

{

FILE *fp;

int j;

//获取背包问题信息文件

if ((fp=fopen("data.txt","r"))==NULL)

{

//读取文件失败

//AfxMessageBox("The file is not found",MB_OK,NULL);

return;

}

//读入物体收益信息

for (j=0;j

{

fscanf(fp,"%d",&profit[j]);

}

//读入物体重量信息

for (j=0;j

{

fscanf(fp,"%d",&weight[j]);

}

//读入背包容量

fscanf(fp,"%d",&bagweight);

fclose(fp);

}

//根据计算的个体重量,判断此个体是否该留在群体中

double cal_weight(unsigned int *chr)

{

int j;

double pop_weight;//背包重量

pop_weight=0;

for (j=0;j

{

pop_weight=pop_weight+(*chr)*weight[j];

chr++;

}

return pop_weight;

}

double cal_fit(unsigned int *chr)

{

int j;

double pop_profit;//适应度

pop_profit=0;

//

pop_weight=0;

for (j=0;j

{

pop_profit=pop_profit+(*chr)*profit[j];

//

pop_weight=pop_weight+(*chr)*weight[j];

chr++;

}

return pop_profit;

}

void

statistics(struct population *pop)

{

int

i;

double

tmp_fit;

sumfitness=pop[0].fitness;

minfitness=pop[0].fitness;

minpop=0;

maxfitness=pop[0].fitness;

maxpop=0;

for

(i=1;i

{

//计算种群的总适应度

sumfitness=sumfitness+pop[i].fitness;

tmp_fit=pop[i].fitness;

//选择种群中最大适应度的个体

if

((tmp_fit>maxfitness)&&((int)(tmp_fit*10)==0))

{

maxfitness=pop[i].fitness;

maxpop=i;

}

//选择种群中最小适应度的个体

if

(tmp_fit

{

minfitness=pop[i].fitness;

minpop=i;

}

//计算平均适应度

avgfitness=sumfitness/(float)zhongqun_size;

}

//

printf("\nthe max pop = %d;",maxpop);

//

printf("\nthe min pop = %d;",minpop);

//

printf("\nthe sumfitness = %f\n",sumfitness);

}

//报告种群信息

void

report(struct population *pop,int gen)

{

int j;

int

pop_weight=0;

printf("the generation is %d.\n",gen); //输出种群的代数

//输出种群中最大适应度个体的染色体信息

printf("The population's chrom is: \n");

for

(j=0;j

{

if

(j%5==0)

{ printf("

");}

printf("",pop[maxpop].chrom[j]);

}

//输出群体中最大适应度

printf("\nThe population's max fitness is

%d.",(int)pop[maxpop].fitness);

printf("\nThe knapsack weight is

%d.\n\n",(int)pop[maxpop].weight);

}

void

initpop()

{

int i,j,ispop;

double tmpWeight;

//变量用于判断是否为满足条件的个体

ispop=false;

//生成zhongqun_size个种群个体

for(i=0;i

{

while (!ispop)

{

for(j=0;j

{

oldpop[i].chrom[j]=rand()%2;

//随机生成个体的染色体

oldpop[i].parent1=0; //双亲

oldpop[i].parent2=0;

oldpop[i].cross=0;

//交叉点

}

//选择重量小于背包容量的个体,即满足条件

tmpWeight=cal_weight(oldpop[i].chrom);

if (tmpWeight<=bagweight)

{

oldpop[i].fitness=cal_fit(oldpop[i].chrom);

oldpop[i].weight=tmpWeight;

oldpop[i].parent1=0;

oldpop[i].parent2=0;

oldpop[i].cross=0;

ispop=true;

}

}

//此个体可以加入到种群中

ispop=false;

}

}

//概率选择试验

int

execise(double probability)

{

double pp;

//如果生成随机数大于相应的概率则返回真,否则试验不成功

pp=(double)(rand()

001/20000.0);

if

(pp<=probability) return 1;

return 0;

}

// 选择进行交叉操作的个体

int

selection(int pop)

{

double wheel_pos,rand_Number,partsum;

int parent;

//赌轮法选择

rand_Number=(rand() 01)/2000.0;

wheel_pos=rand_Number*sumfitness; //赌轮大小

partsum=0;

parent=0;

do{

partsum=partsum+oldpop[parent].fitness;

parent=parent+1;

}

while (partsum

&&

parent

return parent-1;

}

int

crossover(unsigned int *parent1,unsigned int *parent2,int

i)

{

int

j,cross_pos;

if

(execise(pc))

{

//生成交叉位置0,1,...(chrom_length-2)

cross_pos=rand()%(chrom_length-1);

}

else

cross_pos=chrom_length-1;

for

(j=0;j<=cross_pos;j++)

{

//保留复制;

//包括在概率选择不成功时,父体完全保留

newpop[i].chrom[j]=parent1[j];

}

for(j=cross_pos+1;j<=(chrom_length-1);j++)

{

//从交叉点开始交叉

newpop[i].chrom[j]=parent2[j];

}

//记录交叉位置

newpop[i].cross=cross_pos;

return 1;

}

int

mutation(unsigned int alleles)

{

if

(execise(pm))

{

if (alleles)

alleles=0;

else alleles=1;

}

//返回变异值,或者返回原值

return alleles;

}

void

generation()

{

unsigned int i,j,mate1,mate2;

double tmpWeight;

int ispop;//记录是否是符合条件的个体

i=0;

while (i

{

ispop=false;

while (!ispop)

{

//选择

mate1=selection(i);

mate2=selection(i+1);

//交叉

crossover(oldpop[mate1].chrom,oldpop[mate2].chrom,i);

//变异

for (j=0;j

{

newpop[i].chrom[j]=mutation(newpop[i].chrom[j]);

}

//选择重量小于背包容量的个体,即满足条件

tmpWeight=cal_weight(newpop[i].chrom);

if (tmpWeight<=bagweight)

{

newpop[i].fitness=cal_fit(newpop[i].chrom);

newpop[i].weight=tmpWeight;

newpop[i].parent1=mate1;

newpop[i].parent2=mate2;

ispop=true;

}

}

//此个体可以加入到种群中

i=i+1;

}

}

void

main(int argc, char* argv[])

{

int gen,oldmaxpop,k;

double oldmax;

read_infor();//读入背包信息

gen=0;

srand( (unsigned)time( NULL ) );//置随机种子

initpop();

memcpy(&newpop,&oldpop,zhongqun_size*sizeof(struct

population));

statistics(newpop);//统计新生种群的信息

report(newpop,gen);

while(gen

{

gen=gen+1;

if (gen0==0)

{

srand( (unsigned)time( NULL ) );//置随机种子

}

oldmax=maxfitness;

oldmaxpop=maxpop;

generation();

statistics(newpop); //统计新生代种群信息

//如果新生代种群中个体的最大适应度小于老一代种群

//个体的最大适应度,则保存老一代种群个体的最大适应度

//否则报告新生代的最大适应度

if (maxfitness

{

for(k=0;k

newpop[minpop].chrom[k]=oldpop[oldmaxpop].chrom[k];

newpop[minpop].fitness=oldpop[oldmaxpop].fitness;

newpop[minpop].parent1=oldpop[oldmaxpop].parent1;

newpop[minpop].parent2=oldpop[oldmaxpop].parent2;

newpop[minpop].cross=oldpop[oldmaxpop].cross;

statistics(newpop);

}

else if (maxfitness>oldmax)

{

report(newpop,gen);

}

//保存新生代种群的信息到老一代种群信息空间

memcpy(&oldpop,&newpop,zhongqun_size*sizeof(struct

population));

}

printf("It is over.");

getch();

}

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值