遗传算法求解TSP问题
Posted Michael2397
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了遗传算法求解TSP问题相关的知识,希望对你有一定的参考价值。
package com.louis.tsp; /** * Project Name:GeneticAlgorithm * File Name:Individual.java * Package Name: * Date:2017年9月23日下午5:02:00 * Copyright (c) 2017, [email protected] All Rights Reserved. * */ /** * ClassName:Individual * Function: 个体类 * Reason: TODO ADD REASON. * Date: 2017年9月23日 下午5:02:00 * @author michael * @version * @since JDK 1.7 * @see */ public class Individual { //定义染色体,染色体是要很多基因组成 private int[] chromosome; //定义个体实现度,默认值是-1 private double fitness = -1; /* * 通过特定染色体创建个体 * */ public Individual(int[] chromosome){ this.chromosome = chromosome; } public Individual(int chromosomeLength) { int[] individual; individual = new int[chromosomeLength]; //按顺序生成初始基因 for (int gene = 0; gene < chromosomeLength; gene++) { individual[gene] = gene; } this.chromosome = individual; } /* * get 个体的基因 * */ public int[] getChromosome(){ return this.chromosome; } /* * get 基因的长度 * */ public int getChromosomeLength(){ return this.chromosome.length; } /* * 在特定的地方设置基因 * */ public void setGene(int offset,int gene){ this.chromosome[offset] = gene; } /* * 在特定的地方得到基因 * */ public int getGene(int offset){ return this.chromosome[offset]; } /* * 设置个体适应度 * */ public void setFitness(double fitness){ this.fitness = fitness; } /* * 得到个体适应度 * */ public double getFitness(){ return this.fitness; } /* * 染色体(即所有基因)以字符串的形式打印 * */ public String toString(){ String output = ""; for (int gene = 0; gene < this.chromosome.length; gene++) { output +=this.chromosome[gene]; } return output; } /* * 判断是否包含该基因 * */ public boolean containsGene(int gene) { for (int i = 0; i < this.chromosome.length; i++) { if (this.chromosome[i] == gene) { return true; } } return false; } }
package com.louis.tsp; import java.util.Arrays; import java.util.Comparator; import java.util.Random; import org.apache.jasper.tagplugins.jstl.core.If; /** * Project Name:GeneticAlgorithm * File Name:Population.java * Package Name: * Date:2017年9月23日下午7:44:55 * Copyright (c) 2017, [email protected] All Rights Reserved. * */ /** * ClassName:Population * Function: 种群类 * Reason: TODO ADD REASON. * Date: 2017年9月23日 下午7:44:55 * @author michael * @version * @since JDK 1.7 * @see */ public class Population { //种群:所有个体的集合 public Individual[] population; //种群适应度 public double populationFitness=-1; /* * 初始化一个空的种群,参数是种群的大小 * */ public Population(int populationSize){ this.population = new Individual[populationSize]; } /* * 初始化种群,参数是:(1)种群的大小,(2)染色体的长度 * */ public Population(int populationSize,int chromosomeLength){ //新建一个种群,即所有个体的集合 this.population = new Individual[populationSize]; //创建种群中的每个个体 for (int individualCount = 0; individualCount < populationSize; individualCount++) { //调用Individual类的构造方法,创建个体 Individual individual = new Individual(chromosomeLength); //将该个体添加到种群中 this.population[individualCount] = individual; } } /* * 从种群中得到所有个体 * */ public Individual[] getIndividuals(){ return this.population; } /* *通过个体适应度选择一个个体 *先将种群进行排序,最后获得第offset位置的个体 *按适应度顺序排列个体 *从高到底排序 * */ public Individual getFittest(int offset){ //对种群中的个体按照适应度进行排序 Arrays.sort(this.population, new Comparator<Individual>() { @Override public int compare(Individual o1, Individual o2) { if(o1.getFitness()>o2.getFitness()){ return -1; } else if(o1.getFitness()<o2.getFitness()){ return 1; } return 0; } //Arrays.sort(数组,比较器<数组类型>) }); //返回排序第offset的个体 return this.population[offset]; } /* * 得到种群适应度 * */ public double getPopulationFitness() { return populationFitness; } /* * 设置种群适应度 * */ public void setPopulationFitness(double populationFitness) { this.populationFitness = populationFitness; } /* * 得到种群的大小 * */ public int size(){ return this.population.length; } /* * 在第offset位置设置个体 * */ public Individual setIndividual(int offset,Individual individual){ return population[offset] = individual; } /* * 得到第offset位置的个体 * */ public Individual getIndividual(int offset){ return population[offset]; } /* * 随机洗牌 * */ public void shuffle() { Random rnd = new Random(); for (int i = population.length - 1; i > 0; i--) { int index = rnd.nextInt(i + 1); Individual a = population[index]; population[index] = population[i]; population[i] = a; } } }
/** * Project Name:GeneticAlgorithm * File Name:City.java * Package Name:com.louis.tsp * Date:2017年10月5日下午4:29:03 * Copyright (c) 2017, [email protected] All Rights Reserved. * */ package com.louis.tsp; /** * ClassName:City * Function: TODO ADD FUNCTION. * Reason: TODO ADD REASON. * Date: 2017年10月5日 下午4:29:03 * @author michael * @version * @since JDK 1.7 * @see */ public class City { private int x; private int y; public City(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } public double distanceFrom(City city){ double deltaXSq = Math.pow((city.getX() - this.getX()), 2); double deltaYSq = Math.pow((city.getY() - this.getY()), 2); double distance = Math.sqrt(Math.abs(deltaXSq + deltaYSq)); return distance; } }
/** * Project Name:GeneticAlgorithm * File Name:Route.java * Package Name:com.louis.tsp * Date:2017年10月5日下午4:49:45 * Copyright (c) 2017, [email protected] All Rights Reserved. * */ package com.louis.tsp; /** * ClassName:Route * Function: TODO ADD FUNCTION. * Reason: TODO ADD REASON. * Date: 2017年10月5日 下午4:49:45 * @author michael * @version * @since JDK 1.7 * @see */ public class Route { private City route[]; private double distance = 0; //保存当前路线 public Route(Individual individual, City cities[]) { // 获取个体基因,即一条路线 int chromosome[] = individual.getChromosome(); // 将基因转化成路线 this.route = new City[cities.length]; for (int geneIndex = 0; geneIndex < chromosome.length; geneIndex++) { this.route[geneIndex] = cities[chromosome[geneIndex]]; } } //计算线路的总路程 public double getDistance(){ if(this.distance>0){ return this.distance; } double totalDistance = 0; //循环加上路程 for (int cityIndex = 0; cityIndex + 1 < this.route.length; cityIndex++) { totalDistance += this.route[cityIndex].distanceFrom(this.route[cityIndex + 1]); } //最后一个节点与第一个节点之间的路程 totalDistance += this.route[this.route.length - 1].distanceFrom(this.route[0]); this.distance = totalDistance; return totalDistance; } }
package com.louis.tsp; import java.util.Arrays; import com.sun.org.apache.bcel.internal.generic.PopInstruction; /** * Project Name:GeneticAlgorithm * File Name:GeneticAlgorithm.java * Package Name: * Date:2017年9月23日下午8:25:25 * Copyright (c) 2017, [email protected] All Rights Reserved. * */ /** * ClassName:GeneticAlgorithm * Function: 遗传算法的核心 * Reason: TODO ADD REASON. * Date: 2017年9月23日 下午8:25:25 * @author michael * @version * @since JDK 1.7 * @see */ public class GeneticAlgorithm { /*种群大小*/ private int populationSize; /*变异概率*/ private double mutationRate; /*交叉概率*/ private double crossoverRate; /*精英个体数:种群中最强的个体数。保持原样,不参与交叉和变异*/ private int elitismCount; //锦标大小 private int tournamentSize; /*构造函数*/ public GeneticAlgorithm(int populationSize, double mutationRate, double crossoverRate, int elitismCount, int tournamentSize) { super(); this.populationSize = populationSize; this.mutationRate = mutationRate; this.crossoverRate = crossoverRate; this.elitismCount = elitismCount; this.tournamentSize = tournamentSize; } /* * 调用population的构造方法,使用染色体长度初始化种群 * */ public Population initPopulation(int chromosomeLength){ Population population = new Population(this.populationSize, chromosomeLength); return population; } /* * 计算个体的适应度 * */ public double calcFitness(Individual individual, City cities[]) { // 计算适应度 Route route = new Route(individual, cities); double fitness = 1 / route.getDistance(); // 保存个体适应度 individual.setFitness(fitness); return fitness; } /* * 遍历每个个体评估种群适应度 * */ public void evalPopulation(Population population, City cities[]) { double populationFitness = 0; //遍历每个个体,计算种群适应度 for (Individual individual : population.getIndividuals()) { populationFitness += this.calcFitness(individual, cities); } double avgFitness = populationFitness / population.size(); population.setPopulationFitness(avgFitness); } /* * 判断终止的条件,最大代数 * */ public boolean isTerminationConditionMet(int generationsCount, int maxGenerations) { return (generationsCount > maxGenerations); } /* * 选择交叉的个体 * */ public Individual selectParent(Population population) { // 创建用于锦标赛的种群 Population tournament = new Population(this.tournamentSize); //随机洗牌 population.shuffle(); // 随机向锦标赛插入个体 for (int i = 0; i < this.tournamentSize; i++) { Individual tournamentIndividual = population.getIndividual(i); tournament.setIndividual(i, tournamentIndividual); } // 返回最好的个体 return tournament.getFittest(0); } /* * 单点交叉:返回一个新的种群 * */ public Population crossoverPopulation(Population population) { // 重新创建一个种群 Population newPopulation = new Population(population.size()); // 按适应度遍历原来的种群 for (int populationIndex = 0; populationIndex < population.size(); populationIndex++) { //因为已经按照适应度对种群进行排序了 Individual parent1 = population.getFittest(populationIndex); // 是否交叉,交叉率大于随机数并且pass掉精英个体 if (this.crossoverRate > Math.random() && populationIndex >= this.elitismCount) { // 通过锦标赛选择第二个父个体 Individual parent2 = this.selectParent(population); //创建空白子代基因组 int offspringChromosome[] = new int[parent1.getChromosomeLength()]; //基因初始值都设为-1 Arrays.fill(offspringChromosome, -1); Individual offspring = new Individual(offspringChromosome); //随机得到parent的两个位置,用于交叉 int substrPos1 = (int) (Math.random() * parent1.getChromosomeLength()); int substrPos2 = (int) (Math.random() * parent1.getChromosomeLength()); //因为不知道随机数哪个值大哪个小,所以先判断下 final int startSubstr = Math.min(substrPos1, substrPos2); final int endSubstr = Math.max(substrPos1, substrPos2); //将落在区域的基因加入到子代基因中 for (int i = startSubstr; i < endSubstr; i++) { offspring.setGene(i, parent1.getGene(i)); } //遍历parent2的基因 for (int i = 0; i < parent2.getChromosomeLength(); i++) { //endSubStr后的位置 int parent2Gene = i + endSubstr; //如果parent2的基因大于了基因长度,则减去基因长度,总的下来还是能找到所有基因 if (parent2Gene >= parent2.getChromosomeLength()) { parent2Gene -= parent2.getChromosomeLength(); } //如果子个体没有这个基因(即城市),则加入他 if (offspring.containsGene(parent2.getGene(parent2Gene)) == false) { // 循环找到子个体空余位置 for (int ii = 0; ii < offspring.getChromosomeLength(); ii++) { // 找到空余位置 if (offspring.getGene(ii) == -1) { //将父基因加入到子基因 offspring.setGene(ii, parent2.getGene(parent2Gene)); break; } } } } // 将子个体加入到种群中 newPopulation.setIndividual(populationIndex, offspring); } else { // 没有交叉的个体直接加入到种群中,精英个体 newPopulation.setIndividual(populationIndex, parent1); } } return newPopulation; } /*变异得到新种群*/ public Population mutatePopulation(Population population){ Population newPopulation = new Population(this.populationSize); //通过适应度遍历当前种群 for (int populationIndex = 0; populationIndex < population.size(); populationIndex++) { //按照从小到大的顺序选择个体 Individual individual = population.getFittest(populationIndex); //遍历个体的基因 for (int geneIndex = 0; geneIndex < individual.getChromosomeLength(); geneIndex++) { if(populationIndex>this.elitismCount){ //判断该基因是否变异 if (this.mutationRate > Math.random()) { //随机找到要交换的位子 int newGenePos = (int) (Math.random() * individual.getChromosomeLength()); // 得到两个交换位置的值 int gene1 = individual.getGene(newGenePos); int gene2 = individual.getGene(geneIndex); // 交换基因 individual.setGene(geneIndex, gene1); individual.setGene(newGenePos, gene2); } } } newPopulation.setIndividual(populationIndex, individual); } return newPopulation; } }
/** * Project Name:GeneticAlgorithm * File Name:TSP.java * Package Name:com.louis.tsp * Date:2017年10月5日下午4:36:39 * Copyright (c) 2017, [email protected] All Rights Reserved. * */ package com.louis.tsp; /** * ClassName:TSP * Function: TODO ADD FUNCTION. * Reason: TODO ADD REASON. * Date: 2017年10月5日 下午4:36:39 * @author michael * @version * @since JDK 1.7 * @see */ public class TSP { public static int maxGenerations = 3000; public static void main(String[] args) { //100个城市 int numCities = 100; City cities[] = new City[numCities]; // 循环随机产生100座城市坐标 for (int cityIndex = 0; cityIndex < numCities; cityIndex++) { int xPos = (int) (100 * Math.random()); int yPos = (int) (100 * Math.random()); //添加到城市数组中 cities[cityIndex] = new City(xPos, yPos); } //初始化基因算法,100个基因,变异概率0.001,交叉概率0.9,精英个体5个 GeneticAlgorithm ga = new GeneticAlgorithm(100, 0.001, 0.9, 2, 5); //初始化种群 Population population = ga.initPopulation(cities.length); //评估种群 ga.evalPopulation(population, cities); //当前种群年代 int generation = 1; while(ga.isTerminationConditionMet(generation, maxGenerations)==false){ //从种群中选择最优的个体:即可以打印出在该最优情况下的路线 Route route = new Route(population.getFittest(0), cities); System.out.println("G"+generation+" 最好距离: " + route.getDistance()); //交叉 population = ga.crossoverPopulation(population); //变异 population = ga.mutatePopulation(population); //评估 ga.evalPopulation(population, cities); //迭代 generation++; } //展示结果 System.out.println("结束" + maxGenerations + " 次迭代"); Route route = new Route(population.getFittest(0), cities); System.out.println("最好距离: " + route.getDistance()); } }
以上是关于遗传算法求解TSP问题的主要内容,如果未能解决你的问题,请参考以下文章