遗传算法解决0-1背包问题

一:问题描述

         给定n种物品,物品i(1≤i≥n)的体积为wi,价值为vi,将这n种物品放入容量为C的背包之中。在放入背包的物品总体积小于C的情况下,求放入背包物品的最大价值。

 

二:基本实现原理

         1:编码

                            问题可以表示为一个n位的二进制码,第i位表示物品i,数值为0表示物品没有选中,1表示选中物品。

         2:种群

                            种群是个体的集合

         3:适应度

                            适应度在0-1背包问题中表示的是背包中的总价值的大小,总价值越大个体的适应度越大。

         4:选择

                            从种群中选出部分个体之后进行重组或交叉,产生的新个体依据适应度函数进行优胜劣汰,选出优良个体。

         5:交叉

                            不同的个体之间随机的进行杂交,其基因进行再次重组。其后产生新的具有不同适应度的新个体。

         6:变异

                            变异指单个个体的基因按照小概率进行变化的方法。本题中采用的变异方法随机产生变异点,并进行了以下两种变异类型。

1) 变异点进行0和1的状态翻转。此方法趋于常规,但无甚缺点。

2) 变异点变为1,如果超出背包容积,则变为0。此方法更易产生较大的解,但如若初始种群产生的不好,则随后的变异绝不会产生最优解。

 

三:算法实现

 

1:初始化

                   初始化工作包括输入算法的参数,产生初始化种群,种群差异性越明显越好。

2:功能           

                   行数共有以下几种功能:

1)数据结构初始化               

2)种群初始化工作

3)选择操作

4)计算适应度函数功能

5)交叉操作

6)变异操作

7)产生随机数功能

8)最优解记录功能,将进化的每一个种群的最大值与之前产生的最优解进行比较,更大则替换之,否则不替换。

         3:终止条件

                            在遗传一定大的代数时,可以认为产生过了优秀的个体,即最优解(或接近最优解)。

         4:算法步骤

1) 在论域空间U上定义一个适应度函数f(x),给定种群规模N,交叉率Pc和变异率Pm,代数T

2) 随机产生U中的N个染色体s1, s2, …, sN,组成初始种群S={s1, s2,…, sN},置代数计数器t=1;

3) 计算S中每个染色体的适应度f();

4) 若终止条件满足,则取S中适应度最大的染色体作为所求结果,算法结束。

5) 按选择概率P(xi)所决定的选中机会,每次从S中随机选定1个染色体并将其复制,共做N次,然后将复制所得的N个染色体组成群体S1

6) 按交叉率Pc所决定的参加交叉的染色体数c,从S1中随机确定c个染色体,配对进行交叉操作,并用产生的新染色体代替原染色体,得群体S2

7) 按变异率Pm所决定的变异次数m,从S2中随机确定m个染色体,分别进行变异操作,并用产生的新染色体代替原染色体,得群体S3

8) 将群体S3作为新一代种群,即用S3代替St=t+1,转步3;

5:编程设计

1) 类的设计:

1:class Global {

publicfinal static int M =200;                                       //种群的规模

publicfinal static int T = 1000;                                     //遗传的最大代数

publicfinal static double pc = 0.8;                      //交叉率

publicfinal static double pv = 0.05;                   //变异率

}                           

2:class MaxValue{

publicstatic int[] have = null;                     //最大解选择到的物品

publicstatic int max_value = 0;                          //最大解的价值

}

3:public class GasolvePackage

                            2)

                                     类的功能:

Global类中定义的相当于全局变量。

MaxValue类中记录最优解,have数组记录选择的到的物品,max_value记录最优解得价值

GasolvePackage类有遗传算法的各种函数

3)

函数设计:此中具体介绍一下两种最主要的部分

1:GasolvePackage类的构造器

    public GasolvePackage(){

        try{

            BufferedReaderread=newBufferedReader(newInputStreamReader(newFileInputStream(“input.txt”)));

            Stringa=newString();

            Stringb=newString();

            package_rj=Integer.parseInt(read.readLine().trim());      //读取背包容积

            a=read.readLine();                                  //读取物品体积行

            tiji=strArr_to_intArr(a.split(” “));   

            b=read.readLine();                                  //读取物品价值行

            value =strArr_to_intArr(b.split(” “));

            num=value.length;

            MaxValue.have=new int[Global.M];

            read.close();

        }

        catch(Exception e)

        {

            System.out.println(请检查输入文件中的错误);

        }

}                                              

private int[]strArr_to_intArr(String[] strArr){         //将字符数组转化为数字数组

        int size = strArr.length;

        int[] int_arr = new int[size];

       

        for(int i = 0; i < size; i++){

            int_arr[i]= Integer.valueOf(strArr[i]);

        }

        return int_arr;

                     }

此中主要从文本中输入背包容积,各个物品的体积以及各个物品的价值。

2:

    public int[][] variation(int[][]cross_zq){             //变异算法

        int i = 0;

        int row_id = 0;

        int col_id = 0;

        Randomrand =newRandom();

        int variation_num = (int)(Global.pv * Global.M * num);//参与变异的基因个数

        int[][] variation_zq = new int[Global.M][num];

        variation_zq= dCopy(cross_zq);

        for(i = 0; i <variation_num; i ++){

            row_id= rand.nextInt(Global.M);

            col_id= rand.nextInt(num);

            variation_zq[row_id][col_id]= 1-variation_zq[row_id][col_id];

//第二种变异为variation_zq[row_id][col_id] = 1;

            if(get_singleWeight(variation_zq[row_id])> package_rj){

                variation_zq[row_id][col_id]= 1-variation_zq[row_id][col_id];

//第二种变异为variation_zq[row_id][col_id] = 0;

            }

         }

         return variation_zq;

    }  

四:测试结果(算例及四次随机测试结果)

五:程序源代码及其基本注释

import java.io.*;

import java.util.*;

 classMaxValue{

         publicstatic int[] have = null;                     //最大解选择到的物品

         publicstatic int max_value = 0;                          //最大解的价值

}

 classGlobal {

         publicfinal static int M =200;                                       //种群的规模

         publicfinal static int T = 1000;                                     //遗传的最大代数

         publicfinal static double pc = 0.8;                      //交叉率

         publicfinal static double pv = 0.05;                   //变异率

}

public class GasolvePackage {

         privateint package_rj = 0;                                                      //背包的容量

         privateint num = 0;                                                         //物品的个数

         privateint[]tiji = null;                                                      //物品的容积

         privateint[]value = null;                                                 //物品的价值

         privateint[][] zq = null;                                                   //种群

         publicGasolvePackage(){

                   try{

                            BufferedReaderread=new BufferedReader(new InputStreamReader(newFileInputStream(“input.txt”)));

                            Stringa=new String();

                            Stringb=new String();

                            package_rj=Integer.parseInt(read.readLine().trim());

                            a=read.readLine();

                            tiji=strArr_to_intArr(a.split(“”));   

                            b=read.readLine();

                            value= strArr_to_intArr(b.split(” “));

                            num=value.length;

                            MaxValue.have=newint[Global.M];

                            read.close();

                   }

                   catch(Exceptione)

                   {

                            System.out.println(“请检查输入文件中的错误”);

                   }

         }

         //字符串数组转换为整数数组

         privateint[] strArr_to_intArr(String[] strArr){

                   intsize = strArr.length;

                   int[]int_arr = new int[size];

                  

                   for(inti = 0; i < size; i ++){

                            int_arr[i]= Integer.valueOf(strArr[i]);

                   }

                   returnint_arr;

         }

         privateint[][] dCopy(int[][] source){           //二维数组的复制

                   introw_num = source.length;

                   intcol_num = source[0].length;

                  

                   int[][]des = new int[row_num][col_num];

                   for(inti = 0; i < row_num; i ++){

                            for(intj = 0; j < col_num; j ++){

                                     des[i][j]= source[i][j];

                            }

                   }

                   returndes;

         }

         //产生初始种群

         publicint[][] init(){

                   Randomrand=new Random();

                   zq= new int[Global.M][num];

                   for(inti = 0; i < Global.M; i ++){

                            for(intj = 0; j <num; j ++){

                                     zq[i][j] = rand.nextInt(2);

                                    

                            }

                            if(get_singleWeight(zq[i])> package_rj){

                                     i–;

                            }

                   }

                   returnzq;

         }

         //计算个体的总重量

         privateint get_singleWeight(int[] single){

                   inttotal_weight = 0;

                   intsize = single.length;

                  

                   for(inti = 0; i < size; i ++){

                                     total_weight+= tiji[i]*single[i];

                   }

                   returntotal_weight;

         }

        

         //计算个体的总价值

         privateint get_singleValue(int[] single){

                   inttotal_value = 0;

                   intsize = single.length;

                  

                   for(inti = 0; i < size; i ++){

                                     total_value+= value[i]*single[i];

                   }

                   returntotal_value;

         }

         //获取总价值最大的个体

         publicvoid get_maxValue_single(int[][] popu){

                   intsize = popu.length;

                   int[]fitness = new int[size];

                   for(inti = 0; i < size; i ++){

                            fitness[i]= get_singleValue(popu[i]);

                   }

                  

                   intid = 0;

                   intmax_value = fitness[0];

                   for(intj = 1; j < size; j ++){

                            if(fitness[j]> max_value){

                                     max_value= fitness[j];

                                     id= j;

                            }

                   }

                   if(max_value> MaxValue.max_value){

                            MaxValue.max_value= max_value;

                           

                            int[]have = new int[num];

                            for(inti = 0; i < num; i ++){

                                     have[i]= popu[id][i];

                            }

                            MaxValue.have= have;

                   }

         }

         //计算每个个体的适应度

         publicdouble[] getFitness(int[][] popu){

                   intsize = popu.length;

                   double[]fitness = new double[size];

                   for(inti = 0; i < size; i ++){

                            fitness[i]= get_singleValue(popu[i]);

                   }

                   returnfitness;

         }

         //计算每个个体的选择概率

         privatedouble[] get_selectRate(double[] fitness){

                   doublesum = 0;

                   intsize = fitness.length;

                   double[]select_rate = new double[size];

                  

                   for(inti = 0; i < size; i ++){

                            sum+= fitness[i];

                   }

                   for(intj = 0; j < size; j ++){

                            select_rate[j]= fitness[j]/sum;

                   }

                   returnselect_rate;

         }

         //计算每个个体的圆盘概率

         privatedouble[] get_accuRate(double[] select_rate){

                   inti = 0;

                  

                   double[]accu_rate = new double[select_rate.length];

                  

                   for(i= 0; i < select_rate.length; i ++){

                            accu_rate[i]= select_rate[i];

                   }

 

                   for(i= 1; i < select_rate.length; i ++){

                            accu_rate[i]+= accu_rate[i-1];

                   }

                   returnaccu_rate;

         }

         publicint[][]select(double[]select,int[][]zhong)                 //选择产生新的种群

         {

                   Randomrand=new Random();

                   doublet=0;

                   int[][]ans=new int[Global.M][num];

                   for(inti=0;i<zhong.length;i++)

                            for(intj=0;j<zhong[0].length;j++)

                                     ans[i][j]=zhong[i][j];

                   for(inti=0;i<Global.M;i++)

                   {

                            t=rand.nextInt(101)/100;

                            for(intj=0;j>num;j++)

                                     if(t<=select[j])

                                     {

                                               for(intp=0;p<num;p++)

                                                        ans[i][p]=zhong[j][p];

                                              break;

                                     }

                   }

                   returnans;

         }

         //交叉

         publicint[][] crossover(int[][] select_zq){

                    int i = 0;

                    Random rand =new Random();

                    int random_pos = 0, temp = 0;//交换基因的位置

                    int cross_num = (int)(Global.pc * Global.M);//参与交换的个体数

                    int[][] cross_popu = new int[Global.M][num];

                    cross_popu = dCopy(select_zq);

                    for(i = 1; i < cross_num; i += 2){

                             random_pos = rand.nextInt(num);

                             temp = cross_popu[i][random_pos];

                             cross_popu[i][random_pos]=cross_popu[i-1][random_pos];

                             cross_popu[i-1][random_pos] = temp;

                             if(get_singleWeight(cross_popu[i]) >package_rj || get_singleWeight(cross_popu[i-1]) > package_rj){

                                      temp = cross_popu[i][random_pos];

                                      cross_popu[i][random_pos]=cross_popu[i-1][random_pos];

                                      cross_popu[i-1][random_pos] = temp;

                             }

                    }

                    return cross_popu;

         }

         //变异算法1

         publicint[][] variation(int[][] cross_zq){

                   inti = 0;

                   introw_id = 0;

                   intcol_id = 0;

                   Randomrand =new Random();

                   intvariation_num = (int)(Global.pv * Global.M * num);//参与变异的基因个数

                   int[][]variation_zq = new int[Global.M][num];

                   variation_zq= dCopy(cross_zq);

                   for(i= 0; i < variation_num; i ++){

                            row_id= rand.nextInt(Global.M);

                            col_id= rand.nextInt(num);

                            variation_zq[row_id][col_id]= 1-variation_zq[row_id][col_id];

                            if(get_singleWeight(variation_zq[row_id])> package_rj){

                                     variation_zq[row_id][col_id]= 1-variation_zq[row_id][col_id];

                            }

                    }

                    return variation_zq;

         }       

/*    publicint[][] variation(int[][] cross_zq){          //变异算法2

                   inti = 0;

                   introw_id = 0;

                   intcol_id = 0;

                   Randomrand =new Random();

                   intvariation_num = (int)(Global.pv * Global.M * num);//参与变异的基因个数

                   int[][]variation_zq = new int[Global.M][num];

                   variation_zq= dCopy(cross_zq);

                   for(i= 0; i < variation_num; i ++){

                            row_id= rand.nextInt(Global.M);

                            col_id= rand.nextInt(num);

                            variation_zq[row_id][col_id]=1;

                            if(get_singleWeight(variation_zq[row_id])> package_rj){

                                     variation_zq[row_id][col_id]= 0;

                            }

                    }

                    return variation_zq;

         }       

 

*/

         //遗传算法

         publicvoid allway(){

                   intpopu_id = 1;        //总群的代数

                   double[]fitness = null;

                   double[]select_rate = null;

                   double[]accu_rate = null;

                   int[][]select_popu = null;

                   int[][]cross_popu = null;

                   int[][]popu = init();

                   get_maxValue_single(popu);

                   while(popu_id< Global.T){//没有终止

                            fitness= getFitness(popu);

                            select_rate= get_selectRate(fitness);

                            accu_rate= get_accuRate(select_rate);

                            select_popu= select(accu_rate, popu);

                            cross_popu= crossover(select_popu);

                            popu= variation(cross_popu);//下一代总群

                            popu_id++;

                            get_maxValue_single(popu);

                   }

         }

         //输出

         publicvoid show(){

                   System.out.print(“背包容积:”);

                   System.out.println(package_rj);

                            System.out.print(“选择物品的体积:”);

                            for(intj = 0; j < num; j ++){

                                     if(MaxValue.have[j]== 1){

                                               System.out.print(tiji[j]+ ” “);

                                     }

                            }

                            intMaxHeight=0;

                            for(inti=0;i<num;i++)

                                     MaxHeight+=MaxValue.have[i]*tiji[i];

                            System.out.println();

                            System.out.print(“选择物品的总体积:”);

                            System.out.println(MaxHeight);

                            System.out.print(“选择物品的价值:”);

                            for(intj = 0; j <num; j ++){

                                     if(MaxValue.have[j]== 1){

                                               System.out.print(value[j]+ ” “);

                                     }

                            }

                            System.out.println();

                            System.out.print(“物品的总价值:”);

                            System.out.print(MaxValue.max_value);

                  

         }

         publicstatic void main(String[] args){

                   GasolvePackagega = new GasolvePackage();

                   ga.allway();

                   ga.show();

         }

}

六:心得体会

为了做本次的遗传算法解决0-1背包问题的程序,几乎又重新翻阅了一遍java书籍,许多不大懂的问题都上网仔细查阅资料(如:文件输入,字符型转为数字,随机数的实现……)

但刚开始的时候,程序虽说已经做好,但产生的最优解却始终停留在900上下,很少能够达到1000。

如:

我分析可能有以下几种情况,种群初始化不行,或最优解实际并没有找到。于是我重新设计了产生随机数的代码;设计了MaxValue类记录产生的所有种群的最优解;并对变异一段改造,使其进行了我所谓的引导变异,即是使个体向大处变异,从而总体上提升了算法产生最优解的能力。

在随后的测试中,产生的结果全部大于1000,产生最优解1042的概率也明显提升。

在本次应用遗传算法中,提高了自己的编程技巧,深刻的体会到了随机算法的便利性,获得了对随机算法更深的理解及应用能力。

    原文作者:遗传算法
    原文地址: https://blog.csdn.net/lonerdai/article/details/42012265
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞