您的位置:首页 > 其它

基因算法解决01背包问题

2015-12-18 19:26 411 查看
                                                                  

背包问题简述:
有m个物体,每个物体价值为v[i],重量为w[i],有一个背包,最多能盛重量为W的物体,

 求背包能盛的最大的价值。


基因算法:

编码:编码长度为物体的个数,1表示放进包,0表示不放进包

适应度:包里物品的价值和

交叉:两个随机,采用多点交叉,交叉点的个数是随机的,交叉的位置是随机的

编译:同样两个随机

交叉概率:0.8

变异概率:0.15

个体类(一个个体就是问题的一个解):

import java.util.Arrays;

/**
* 0 1背包中的个体,一个个体对应基因算法的一个解
* @author founder
*/
public class Individual {

//基因序列,数组的大小为物体的个数,gene[i]=1表示选择,gene[i]=0表示不选择
public int[] gene;
public double fitness; //个体的适应度
public double selectProbability; //选择概率
public double accumulateProbability; //累积的选择概率

public Individual(Individual ind){
this.gene = new int[ind.gene.length];
this.gene = Arrays.copyOf(ind.gene, ind.gene.length);
this.fitness = ind.fitness;
this.selectProbability = ind.selectProbability;
this.accumulateProbability = ind.accumulateProbability;
}

public Individual(){
}
}

全部代码如下,evaluate给出每个解的评估,crossover交叉操作,mutation编译操作,迭代次数为100,种群大小为50。

代码实现了两种选择算子,轮盘赌算法和二进制锦标赛算法



import java.util.Arrays;
import java.util.Random;

/**
* 基因算法解决0 1背包问题,背包问题简述:
* 有m个物体,每个物体价值为v[i],重量为w[i],有一个背包,最多能盛重量为W的物体,
* 求背包能盛价值最大的物体
* @author founder
*/
public class BinPacking {

public int[] bin_values;	//价值向量
public int[] bin_weights;	//重量向量
public int bin_capacity;	//背包可以承受的总重量
public int bin_objNum;

public int gene_N;			//种群大小
public double gene_cross_prob = 0.8;
public double gene_mutation_prob = 0.15;

public Individual[] population;

public Random random;

/**
* 构造函数
* @param num	物体个数
* @param gene_N	种群大小
*/
public BinPacking(){

this.bin_objNum = 7;	//物体个数
this.gene_N = 40;		//种群中的个体个数

population = new Individual[gene_N];

int[] bin_values = {10,40,30,50,35,40,30};
this.bin_values = bin_values;

int[] bin_weights = {35,30,60,50,40,10,25};
this.bin_weights = bin_weights;

this.bin_capacity = 150;

this.random = new Random(System.currentTimeMillis());
}

/**
* 随机产生大小为N的种群
* Random.nextInt(n)从0(包含)到n(不包含)均匀分布的整数
*/
public void generateInitPopulation(){

for(int i=0;i<this.gene_N;i++){
Individual ind = new Individual();
ind.gene = new int[this.bin_objNum];
for(int j=0;j<ind.gene.length;j++){
ind.gene[j] = random.nextInt(2);
}
population[i] = ind;
}
}

/**
* 计算每个个体的适应度,顺便计算整个种群的适应度
* @param Individual[] inds,一整个种群
* @return 种群总的适应度,所有个体的适应度的和(用来计算选择概率)
*/
public void evaluate(){
int totalFitness = 0;

for(int i=0;i<this.population.length;i++){			//计算每个个体的适应度以及种群的总适应度
Individual ind = this.population[i];
int weight = 0;
ind.fitness = 0;
for(int j=0;j<ind.gene.length;j++){
if(ind.gene[j]==1){
ind.fitness += bin_values[j];
weight += bin_weights[j];
}
}

if(weight > bin_capacity){
ind.fitness = 1;
}
totalFitness += ind.fitness;
}

double lastcf = 0.0;
for(int i=0;i<this.population.length;i++){		//计算每个个体的选择概率,以及累加选择概率(轮盘赌)
this.population[i].selectProbability = this.population[i].fitness/totalFitness;
this.population[i].accumulateProbability = lastcf + this.population[i].selectProbability;
lastcf = this.population[i].accumulateProbability;
}

}

/**
* 使用轮盘赌算法选择大小为N的种群
*/
public void select(){
Individual[] newInds = new Individual[this.gene_N];
for(int i=0;i<this.gene_N;i++){		//选择的次数即为种群的大小
double prob = random.nextDouble();
if(prob<this.population[0].accumulateProbability){
newInds[i] = new Individual(this.population[0]);
}else{
for(int j=0;j<this.population.length-1;j++){
if(prob>=this.population[j].accumulateProbability
&& prob<this.population[j+1].accumulateProbability){

newInds[i] = new Individual(this.population[j+1]);
}
}
}
}
this.population = newInds;
}

/**
* 轮盘赌选择算法的另一种选择方法:二进制竞赛
* 随机选择两个,适应度大的作为下一代,适应度小的丢弃
*/
public void binaryCompetitionSelect(){
Individual[] newInds = new Individual[this.gene_N];

for(int i=0;i<newInds.length;i++){
int first = random.nextInt(this.gene_N);
int second = random.nextInt(this.gene_N);

if(this.population[first].fitness>=this.population[second].fitness){
newInds[i] = new Individual(this.population[first]);
}else{
newInds[i] = new Individual(this.population[second]);
}
}

this.population = newInds;
}

/**
* 交叉操作,以某概率,交叉概率设置为0.8
*/
public void crossover(){
int first = -1;
for(int i=0;i<this.population.length;i++){
double prob = random.nextDouble();
if(prob<this.gene_cross_prob){
if(first<0){
first = i;
}else{
exchange(first, i);
first = -1;
}
}
}
}

/**
* 交换两个个体的部分基因(随机个基因),两个随机:
* 1、交换点的个数是随机的
* 2、交换的位置是随机的
*/
public void exchange(int first,int second){
int exNum = random.nextInt(population.length);	//产生交换的基因数
for(int i=0;i<exNum;i++){
//每次选择一个基因进行交换,一共exNum个。
int pos = random.nextInt(this.bin_objNum);
//int temp = population[first].gene[pos];

Individual ind = population[first];
int temp = ind.gene[pos];

population[first].gene[pos] = population[second].gene[pos];
population[second].gene[pos] = temp;
}
}

/**
* 变异操作
*/
public void mutation(){
for(int i=0;i<this.population.length;i++){
if(random.nextDouble()<this.gene_mutation_prob){		//进行变异操作,随机个点,随机位置
int mutNum = random.nextInt(this.population.length);
for(int j=0;j<mutNum;j++){
int pos = random.nextInt(this.bin_objNum);
this.population[i].gene[pos] = 1-this.population[i].gene[pos];
}
}
}
}

public static void startBP(){
BinPacking bp = new BinPacking();
bp.generateInitPopulation();

for(int i=0;i<50;i++){
bp.evaluate();
//bp.select();
bp.binaryCompetitionSelect();
bp.crossover();
bp.mutation();
}

bp.evaluate();

Arrays.sort(bp.population, new IndCom());

System.out.println(bp.population[0].fitness);
for(int i=0;i<bp.population[0].gene.length;i++){
System.out.print(bp.population[0].gene[i]+" ");
}
}

public static void main(String[] args) {
startBP();
}

}


用于对Individual排序的比较器:

import java.util.Comparator;

public class IndCom implements Comparator<Individual>{

@Override
public int compare(Individual o1, Individual o2) {

if(o2.fitness>o1.fitness){
return 1;
}else if(o2.fitness<o1.fitness){
return -1;
}else{
return 0;
}
}

}


基因算法流程图:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: