遗传算法求解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问题的主要内容,如果未能解决你的问题,请参考以下文章

遗传算法求TSP问题

建模算法基于遗传算法求解TSP问题(Python实现)

从零开始实现遗传算法(用遗传算法求解TSP)

从零开始实现遗传算法(用遗传算法求解TSP)

遗传算法求解TSP源码及解析

遗传算法求解TSP问题