遗传算法解决背包问题(java)

遗传算法解决背包问题(java)

遗传算法作为当今一个比较热门的研究方向,在解决最优化问题上有着良好的作用。遗传算法利用基因编码,对其进行生成、杂交、变异、选择等操作,产生不同的基因序列,使解一步一步向最优解逼近。

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

已知n个物体的容积及其价值分别为w_i 和c_i (i=1,2, …,n),背包的总容量为v。问:选择哪些物品 装入背包可以使背包在满足容量限制的前提下总价值最大?

问题

可选择的物品有50件,其价值c和重量v分别为

c={220,208,198,192,180,180,165,162,160,158,155,130,125122,120,118,115,110,105,101,100,100,98,96,95,90,88,82,80,77,75,73,72,70,69,66,65,63,60,58,56,50,30,20,15,10,8, 5,3,1}

w={80,82,85,70,72,70,66,50,55,25,50,55,40,48,50,32,22,60,30,32,40,38,35,32,25,28,30,22,50,30,45,30,60,50,20,65,20,25,30,10,20,25, 15,10,10,10,4,4,2,1}

背包的总量不能超过1000,求解背包所能装下的最大的价值是多少

遗传算法解决思路

利用遗传算法时,可以随机生成一个长度为50的0-1序列,其中1表示对应位置的物品装进背包,0表示对应物品不装进背包,需要注意的是,生成的序列有可能超过背包的总重量,不满足约束条件,此时需要对序列进行操作。可行的操作有两种,第一种是对于不满足约束条件的序列进行抛弃,第二种是对其进行贪心算子变换,具体操作如下:

    对所有 x_1=1 的物品,按它们的价值密度排序,形成队列b(i);
    依次放入价值密度最大的物品,并判断是否有超出背包限定的范围;
    如果超出,则将价值密度序列中从这个位置之后的所有商品置0;


代码

染色体类
 

import java.util.Random;

public class Chromosome {
    public boolean[] gene;
    private int fitness;
    private int bag=1000;



    public int getFitness() {

        return fitness;
    }

    public void setFitness(int fitness) {

        this.fitness = fitness;
    }
    /*
    构造染色体
     */
    public Chromosome(int n){
        if (n<0){
            return;
        }
        initSize(n);
        for(int i=0;i<n;i++){
            gene[i]=Math.random()>=0.5;
        }

        getFitness();
    }
    public Chromosome(){

    }

    public void initSize(int n){
        if (n<0){
            return;
        }
        this.gene=new boolean[n];
    }

    /*
    染色体变异
     */

    public void mutation(int size,double rate){
        Random random=new Random();
        for(int i=0;i<size;i++){
            if(random.nextDouble()<rate){
                boolean t=gene[i];
                t=!t;
                gene[i]=t;
            }
        }


    }



}

遗传算法

import java.util.*;


public class GeneticAlgorith {
    public List<Chromosome> population=new ArrayList<Chromosome>();//存放所有的种群基因
    private int popSize; //种群规模N
    private int chromoLength;//每条染色体数目m;
    private double mutationRate=0.01;//基因突变概率pm
    private  double crossoverRate=0.6;//交叉概率pc
    private int bagMax=1000;

    private int generation;//种群代数t
    private int iterNum=10000;//最大迭代次数
   // private int stepmax=3;//最长步长

    private int [] charge={220,208,198,192,180,180,165,162,160,158,155,130,125,122,120,118,115,110,105,101,100,100,98,96,95,90,88,82,80,77,75,73,72,70,69,66,65,63,60,58,56,50,30,20,15,10,8,5,3,1};
    private int [] weight={80,82,85,70,72,70,66,50,55,25,50,55,40,48,50,32,22,60,30,32,40,38,35,32,25,28,30,22,50,30,45,30,60,50,20,65,20,25,30,10,20,25,15,10,10,10,4,4,2,1};
    private double[]  density=new double[50];

    private Chromosome nowGenome;
    private Chromosome bestFit; //最好适应度对应的染色体
    private Chromosome iterBestFit;//全局最优染色体
    private double bestFitness;//种群最大适应度
    private double worstFitness;//种群最坏适应度
    private double averageFitness;


    private double x1;
    private double x2;
    private double y=0;

    public Chromosome getNowGenome() {
        return nowGenome;
    }


    public void setNowGenome(Chromosome nowGenome) {
        this.nowGenome = nowGenome;
    }

    public Chromosome getIterBestFit() {
        return iterBestFit;
    }

    public void setIterBestFit(Chromosome iterBestFit) {
        this.iterBestFit = iterBestFit;
    }

    public Chromosome getBestFit() {
        return bestFit;
    }

    public void setBestFit(Chromosome bestFit) {
        this.bestFit = bestFit;
    }

    public double getBestFitness() {
        return bestFitness;
    }

    public void setBestFitness(double bestFitness) {
        this.bestFitness = bestFitness;
    }

    public double getWorstFitness() {
        return worstFitness;
    }

    public void setWorstFitness(double worstFitness) {
        this.worstFitness = worstFitness;
    }

    public double getTotalFitness() {
        return totalFitness;
    }

    public void setTotalFitness(double totalFitness) {
        this.totalFitness = totalFitness;
    }

    private double totalFitness;//种群总适应度
    private Random random=new Random();

    public int sumCharge(){
        int sumone=0;
        for(int i=0;i<charge.length;i++){
            sumone+=charge[i];

        }
        return sumone;
    }
    public int sumWeight(){
        int sumtwo=0;
        for(int i=0;i<weight.length;i++){
            sumtwo+=weight[i];

        }
        return sumtwo;
    }


    //构造Getting方法

    public GeneticAlgorith(int popSize){
        this.popSize=popSize;

    }
    /*
    初始化种群
     */
    public void init(){
        for(int i=0;i<charge.length;i++){
            density[i]=charge[i]/weight[i];
        }

        for(int i=0;i<popSize;i++){
            Chromosome g=new Chromosome(50);
            changeGene(g);
            population.add(g);
        }
        caculteFitness();


    }
    /*
    计算种群适应度
     */
    public void caculteFitness(){

        bestFitness=population.get(0).getFitness();
        worstFitness=population.get(0).getFitness();
        totalFitness=0;
        for (Chromosome g:population) {
            //changeGene(g);
            setNowGenome(g);
            if(g.getFitness()>bestFitness){
                setBestFitness(g.getFitness());
                if(y<bestFitness){
                    y=g.getFitness();
                }
                setIterBestFit(g);

            }
            if(g.getFitness()<worstFitness){
                worstFitness=g.getFitness();
            }
            totalFitness+=g.getFitness();

        }
        averageFitness = totalFitness / popSize;
        //因为精度问题导致的平均值大于最好值,将平均值设置成最好值
        averageFitness = averageFitness > bestFitness ? bestFitness : averageFitness;


    }

    /*
    轮盘赌选择算法
     */
    public Chromosome getChromoRoulette(){
        double db=random.nextDouble();
        double randomFitness=db*totalFitness;
        Chromosome choseOne=null;
        double sum=0.0;
        for(int i=0;i<population.size();i++){
            choseOne=population.get(i);
            sum+=choseOne.getFitness();
            if(sum>=randomFitness){
                break;
            }
        }
        return choseOne;

    }


    /*
    clone
    */
    public static Chromosome clone(Chromosome c){
        if (c==null||c.gene==null){
            return null;
        }
        Chromosome copy=new Chromosome();
        copy.initSize(50);
        for (int i=0;i<c.gene.length;i++){
            copy.gene[i]=c.gene[i];
        }
        copy.setFitness(c.getFitness());
        return copy;

    }

    /*
    两点交叉
     */
    public static List<Chromosome> genetic(Chromosome p1,Chromosome p2){
        if(p1==null||p2==null){
            return null;
        }
        if(p1.gene==null||p2.gene==null){
            return null;
        }
        if(p1.gene.length!=p2.gene.length){
            return null;
        }
        Chromosome c1=clone(p1);
        Chromosome c2=clone(p2);
        int size=c1.gene.length;
        int a=(int)(Math.random()*size)%size;
        int b=(int)(Math.random()*size)%size;
        int min=a>b?b:a;
        int max=a>b?a:b;
        if(max-min>15){
            max=min+15;
        }//最大步长为10

        for(int i=min;i<max;i++){
            boolean temp=c1.gene[i];
            c1.gene[i]=c2.gene[i];
            c2.gene[i]=temp;
        }

        c1.setFitness(c1.getFitness());
        c2.setFitness(c2.getFitness());

        List<Chromosome> listNew=new ArrayList<Chromosome>();
        listNew.add(c1);
        listNew.add(c2);
        return listNew;
    }
    /*
    贪心变换算子
     */
    public void changeGene(Chromosome c){
        int flag=0;
        int fitnessNow=0;
        int weightNow=0;
        Map<Integer,Double> map=new TreeMap<Integer, Double>();
        for(int i=0;i<c.gene.length;i++){
            if(c.gene[i]==true){
                map.put(i,density[i]);
            }
        }
        Comparator<Map.Entry<Integer, Double>> valueComparator = new Comparator<Map.Entry<Integer, Double>>() {
            @Override
            public int compare(Map.Entry<Integer, Double> o1, Map.Entry<Integer, Double> o2) {
                return o2.getValue().compareTo(o1.getValue());
            }
        };
        List<Map.Entry<Integer,Double>> list=new ArrayList<Map.Entry<Integer, Double>>(map.entrySet());
        Collections.sort(list,valueComparator);
        for (Map.Entry<Integer,Double> entry:list) {

            if(weightNow+weight[entry.getKey()]<=bagMax){
            //if(flag==0){
                fitnessNow+=charge[entry.getKey()];
                weightNow+=weight[entry.getKey()];
            }
            else{
                //flag=1;
                c.gene[entry.getKey()]=false;
            }

            /*
            fitnessNow+=charge[entry.getKey()];
            weightNow+=weight[entry.getKey()];
            if(weightNow<=bagMax){
                c.setFitness(fitnessNow);
            }
            else{
                c.setFitness(0);
            }
            */
            c.setFitness(fitnessNow);
            
        }







    }
    /*
    进化算法
     */
    public void evolve() {
        List<Chromosome> childrenGenome = new ArrayList<Chromosome>();

        for (int j = 0; j < popSize / 2; j++) {
            Chromosome g1 = getChromoRoulette();
            Chromosome g2 = getChromoRoulette();
            double r = random.nextDouble();

            if (r <= crossoverRate) {
                List<Chromosome> children = genetic(g1, g2);
                if (children != null) {
                    for (Chromosome g : children) {
                        changeGene(g);
                        childrenGenome.add(g);
                        g.mutation(50, mutationRate);
                        changeGene(g);
                        childrenGenome.add(g);
                    }
                }

            }

            childrenGenome.add(g1);
            childrenGenome.add(g2);
        }


        List<Chromosome> temGen = new ArrayList<Chromosome>();
        population.clear();

        for (int i = 0; i < popSize*0.2; i++) {
            int max = 0;

            for (Chromosome tempG : childrenGenome) {
                if (tempG.getFitness() > max) {
                    max = tempG.getFitness();
                    setBestFit(tempG);
                }

            }
            temGen.add(getBestFit());
            childrenGenome.remove(getBestFit());
            setBestFit(null);

        }


        population = childrenGenome;
        caculteFitness();

        while (temGen.size() < popSize) {
            Chromosome tp1 = getChromoRoulette();
            temGen.add(tp1);
        }

        /*
        while (temGen.size()<popSize){
            Chromosome tp1=new Chromosome(50);
            temGen.add(tp1);
        }
        */

        population = temGen;


        //重新计算种群适应度
        caculteFitness();


    }
    /*
    遗传算法GA流程
     */
    public void geneticAlgorithProcess(){
        generation=1;
        init();
        while(generation<iterNum){
            evolve();
            print();

            generation++;

        }
    }

    public void print(){
        System.out.println("this is generation "+generation);
        System.out.println("the best fitness is "+y);
        System.out.println("-----------------------------------------------");
        if(generation==iterNum-1){
            for(int i=0;i<50;i++){
                if(iterBestFit.gene[i]==true){
                    System.out.printf("1");
                }
                else{
                    System.out.printf("0");
                }
                System.out.printf(" ");
            }
            System.out.println("");
        }
    }



}

测试类

public class Test {
    public static void main(String[] args) {
        GeneticAlgorith g=new GeneticAlgorith(100);
        g.geneticAlgorithProcess();
        System.out.println(g.sumCharge());
        System.out.println(g.sumWeight());
        g=null;



    }
}

结果

遗传算法解决背包问题(java)

注意

本题存在两个局部最优解,分别为3103和3098,全局最优解为3103,但是当算法收敛到3098时很难再收敛到3103,这并不代表算法本身有问题,若要每次都求解到全局最优解,需要做进一步的改进,这个问题先留在此处。