初学遗传算法,一个练手的小程序

    最近研究了一下遗传算法,挺有意思的,在一个老外的网站上看到了这个小例子,比较有趣,自己用java实现了一下(老外是用c++实现的)。
    问题:有10张纸牌,编号分别是1到10,现在要将这10张纸牌分为2堆,其中一堆求和为36,另一堆求积为360,问应该怎么分? (也就是说,最终的结果应该是:一堆为2+7+8+9+10=36,另一堆为1*3*4*5*6=360。当然,如果修改题目中的参数,改为32和360,那么结果就是2+3+4+6+7+10=32 和 1*5*8*9=360)
原文地址: http://www.codeproject.com/KB/recipes/Genetic_Algorithm.aspx
另外,这个算法不保证每次都有结果,一般多运行几次是会得到结果的,当然,如果本身无解,那自然是永远也找不到结果的。

  1. package andycpp;
  2. import java.util.Random;
  3. public class CardGA {
  4.     /**
  5.      * @param args
  6.      */
  7.     public static void main(String[] args) {
  8.         new CardGA().run();
  9.     }
  10.     private final int pop_size = 30;        //人口池容量
  11.     private final int chrom_length = 10;    //染色体长度
  12.     private final float crossover_rate = 0.6f;  //杂交率
  13.     private final float mutation_rate = 0.01f;  //变异率
  14.     private final int max_generation = 1000;    //繁殖次数的上限
  15.     private final int sum_tagart = 32;          //纸牌求和的目标值
  16.     private final int product_targart = 360;    //纸牌求积的目标值
  17.     private static Random rand = new Random();  //随机数产生器
  18.     
  19.     private int[][] population = new int[pop_size][chrom_length];   //人口池
  20.     
  21.     public void run() {
  22.         int generation = 0;
  23.         initPopuation(population);
  24.         int winner = 0, loser = 0;
  25.         while(generation < max_generation) {
  26.             generation++;
  27.             winner = rand.nextInt(pop_size);
  28.             loser = rand.nextInt(pop_size);
  29.             if(getFitness(winner) > getFitness(loser)) {
  30.                 int temp = winner;
  31.                 winner = loser;
  32.                 loser = temp;
  33.             }
  34.             if(isAnswer(winner))
  35.                 break;
  36.             crossover(winner, loser);
  37.             mutation(loser);
  38.             if(isAnswer(loser)) {
  39.                 winner = loser;
  40.                 break;
  41.             }
  42.         }
  43.         if(generation == max_generation)
  44.             System.out.println("没找到合适的结果");
  45.         else
  46.             System.out.println("在第"+generation+"代"+parseToString(winner));
  47.     }
  48.     /**
  49.      * 将某个染色体解析为内容友好的字符串
  50.      */
  51.     private String parseToString(int chrom) {
  52.         StringBuilder result = new StringBuilder();
  53.         StringBuilder sum = new StringBuilder();
  54.         StringBuilder prod = new StringBuilder();
  55.         for(int i=0; i<chrom_length; i++) {
  56.             if(population[chrom][i] == 0)
  57.                 sum.append((i+1) + "+");
  58.             else
  59.                 prod.append((i+1) + "*");
  60.         }
  61.         sum.replace(sum.length()-1, sum.length(), "="+sum_tagart);
  62.         prod.replace(prod.length()-1, prod.length(), "="+product_targart);
  63.         result.append("找到了合适的纸牌组合,分别是:" + System.getProperty("line.separator"));
  64.         result.append(sum.toString() + System.getProperty("line.separator"));
  65.         result.append(prod.toString() + System.getProperty("line.separator"));
  66.         
  67.         return result.toString();
  68.     }
  69.     /**
  70.      * 判断某个染色体是否就是最终答案
  71.      */
  72.     private boolean isAnswer(int chrom) {
  73.         if(getFitness(chrom) == 0f) {
  74.             return true;
  75.         }
  76.         return false;
  77.     }
  78.     /**
  79.      * 对染色体进行变异
  80.      */
  81.     private void mutation(int chrom) {
  82.         for(int i=0; i<chrom_length; i++) {
  83.             if(rand.nextFloat()<mutation_rate) {
  84.                 population[chrom][i] = (population[chrom][i]+1)%2;
  85.             }
  86.         }
  87.     }
  88.     /**
  89.      * 将两个染色体进行杂交,winner不变,只修改loser
  90.      */
  91.     private void crossover(int winner, int loser) {
  92.         for(int i=0; i<chrom_length; i++) {
  93.             if(rand.nextFloat()<crossover_rate)
  94.                 population[loser][i] = population[winner][i];
  95.         }
  96.     }
  97.     /**
  98.      * 取得第i个染色体的符合度,符合度越小越好
  99.      */
  100.     private float getFitness(int chrom) {
  101.         int sum = 0;
  102.         int prod = 1;
  103.         for(int i=0; i<chrom_length; i++) {
  104.             if(population[chrom][i]==0)
  105.                 sum += (1+i);
  106.             else
  107.                 prod *= (1+i);
  108.         }
  109.         return (float)Math.abs(sum - sum_tagart)/sum_tagart + (float)Math.abs(prod - product_targart)/product_targart;
  110.     }
  111.     /**
  112.      * 初始化人口池,数组的内容为0或者1,
  113.      * 0标识该扑克牌被分配到求和组
  114.      * 1标识该扑克牌被分配到求积组
  115.      */
  116.     private void initPopuation(int[][] population2) {
  117.         for(int i=0; i<pop_size; i++)
  118.             for(int j=0; j<chrom_length; j++) {
  119.                 if(rand.nextFloat()<0.5f)
  120.                     population[i][j] = 0;
  121.                 else
  122.                     population[i][j] = 1;
  123.             }
  124.         
  125.     }
  126. }

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值