背包问题简述:
有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;
}
}
}
基因算法流程图: