使用遗传算法求解TSP问题

从网上找了一个GA算法的模板,按照自己的理解重写了部分操作。附上注释粘贴如下:

/**
 * 
 */
package ga;

/**
 * @author ly
 *
 */

import java.io.IOException;
import java.util.Arrays;
import java.util.Random;

/**
 * 
 * GA algorithm to solve TSP problem
 */
public class GAalgorithm {
	// population size
	private final static int M = 100;
	// city number
	private int cityNum;

	// total execute number
	private int total;

	// the distance
	private int[][] cityMap;

	// the lowest distance
	private int lowestDistance;

	// the lowest path
	private int[] bestPath;

	// the parent population
	private int[][] parentGeneration;

	// the child population
	private int[][] childGeneration;

	// fitness
	private int[] fitness;

	// probability
	private float[] probability;

	// the probability of cross gene
	private float crossProbability;

	// the probability of gene mutation
	private float mutateProbability;

	// the random number
	private Random random;

	/**
	 * @param total
	 * @param corss
	 * @param mutate
	 * @param map
	 * @param cityNum
	 * 
	 *            using all the parameter to initial the class
	 */
	public GAalgorithm(int total, float corss, float mutate, int[][] map, int cityNum) {
		this.total = total;
		crossProbability = corss;
		mutateProbability = mutate;
		this.cityNum = cityNum;
		cityMap = new int[cityNum][cityNum];
		cityMap = map;
		cityMap[cityNum - 1][cityNum - 1] = 0;
		lowestDistance = Integer.MAX_VALUE;
		bestPath = new int[cityNum + 1];
		childGeneration = new int[M + 1][cityNum + 1];
		parentGeneration = new int[M + 1][cityNum + 1];
		fitness = new int[M];
		probability = new float[M];
		random = new Random(System.currentTimeMillis());
	}

	/**
	 * initial the group
	 */
	void initGroup() {
		int k;
		int[] node = new int[this.cityNum];
		for (int p = 0; p < cityNum; p++) {
			node[p] = p;
		}
		for (k = 0; k < M; k++) {
			// parentGeneration[k][0] = random.nextInt(cityNum);
			parentGeneration[k] = randomInitial(node, cityNum);
		}
	}

	/**
	 * @param node
	 * @param n
	 * @return
	 * 
	 * 		according to the initial list generate a random list
	 */
	public int[] randomInitial(int[] node, int n) {
		int t = 0;
		while (t < 10 * cityNum)
			t = random.nextInt(30 * cityNum);
		for (int i = 0; i <= t; i++) {
			int a = random.nextInt(cityNum);
			int b = random.nextInt(cityNum);

			int c = node[a];
			node[a] = node[b];
			node[b] = c;
		}
		return node;

	}

	/**
	 * calculate the fitness
	 */
	public int evaluate(int[] gene) {
		int len = 0;
		// sum all the distance
		for (int i = 1; i < cityNum; i++) {
			len += cityMap[gene[i - 1]][gene[i]];
		}
		len += cityMap[gene[cityNum - 1]][gene[0]];
		return len;
	}

	/**
	 * calculate the total probably and divide the whole [0,1)
	 */
	void calculateRange() {
		int k;
		double sumFitness = 0;
		for (k = 0; k < M; k++) {
			sumFitness += fitness[k];
		}
		probability[0] = (float) (fitness[0] / sumFitness);
		// the range for choose K will be used in roulette()
		for (k = 1; k < M; k++) {
			probability[k] = (float) (fitness[k] / sumFitness + probability[k - 1]);
		}
	}

	/**
	 * select the high fitness generation of all
	 */
	public void storeBsetGene() {
		int k, i, maxid;
		int maxevaluation;
		maxid = 0;
		maxevaluation = fitness[0];
		for (k = 1; k < M; k++) {
			if (maxevaluation > fitness[k]) {
				maxevaluation = fitness[k];
				maxid = k;
			}
		}
		if (lowestDistance > maxevaluation) {
			lowestDistance = maxevaluation;
			for (i = 0; i < cityNum; i++) {
				bestPath[i] = parentGeneration[maxid][i];
			}
		}
		// store the high fitness generation in position 0;
		copyToNextGeneration(0, maxid);
	}

	/**
	 * select the child generation using roulette gambling
	 */
	public void roulette() {
		int k, i;
		float ran;
		for (k = 1; k < M; k++) {
			ran = random.nextFloat();
			for (i = 0; i < M; i++) {
				if (ran <= probability[i]) {
					break;
				}
			}
			copyToNextGeneration(k, i);
		}
	}

	/**
	 * get the k th child generation from parent generation
	 */
	public void copyToNextGeneration(int k, int j) {
		int i;
		for (i = 0; i < cityNum; i++) {
			childGeneration[k][i] = parentGeneration[j][i];
		}
	}

	/**
	 * the evolution of the group
	 */
	public void evolution() {
		int k;
		storeBsetGene();
		roulette();
		float r;
		for (k = 0; k < M; k = k + 2) {
			r = random.nextFloat();
			// cross k th generation and the k+1 th generation gene
			if (r < crossProbability) {
				geneCrossover(k, k + 1);
			}
			r = random.nextFloat();
			// mutate gene
			if (r < mutateProbability) {
				geneMutate(k);
			}
			r = random.nextFloat();
			if (r < mutateProbability) {
				geneMutate(k + 1);

			}
		}
	}

	/**
	 * @param a
	 * @param b
	 * @return if a has b
	 */
	public boolean containGene(int[] a, int b) {
		for (int i = 0; i < a.length; i++) {
			if (a[i] == b) {
				return true;
			}
		}
		return false;
	}

	/**
	 * crossover gene of the k1 th and k2 th
	 * 
	 * @param k1
	 * @param k2
	 */
	public void geneCrossover(int k1, int k2) {
		int[] child1 = new int[cityNum];
		int[] child2 = new int[cityNum];
		int ran1 = random.nextInt(cityNum);
		int ran2 = random.nextInt(cityNum);
		while (ran1 == ran2) {
			ran2 = random.nextInt(cityNum);
		}
		if (ran1 > ran2) {
			int temp = ran1;
			ran1 = ran2;
			ran2 = temp;
		}
		// store the part that will be switched
		for (int i = ran1; i <= ran2; i++) {
			child1[i] = childGeneration[k1][i];
			child2[i] = childGeneration[k2][i];
		}
		int[] sss1=new int[ran2-ran1+1];
		for(int i=0;i<=ran2-ran1;i++)
		{
			sss1[i]=childGeneration[k1][ran1+i];
		}
		for(int i=ran1;i<=ran2;i++)
		{
			if(!containGene(sss1, child2[i]))
			{
				for(int j=ran1;j<=ran2;j++)
				{
					//为了使得不重不漏,对于child2中不在chileGeneration[k1]中相应位置的元素,要替换为其中的元素
					if(!containGene(child2, childGeneration[k1][j]))
					{
						child2[i]=childGeneration[k1][j];
					}
				}
			}
			
		}
		int[] sss2=new int[ran2-ran1+1];
		for(int i=0;i<=ran2-ran1;i++)
		{
			sss2[i]=childGeneration[k2][ran1+i];
		}
		for(int i=ran1;i<=ran2;i++)
		{
			if(!containGene(sss2, child1[i]))
			{
				for(int j=ran1;j<=ran2;j++)
				{
					if(!containGene(child1, childGeneration[k2][j]))
					{
						child1[i]=childGeneration[k2][j];
					}
				}
			}
			
		}
		for(int i=ran1;i<=ran2;i++)
		{
			childGeneration[k1][i]=child2[i];
			childGeneration[k2][i]=child1[i];
		}

	}

	/**
	 * random mutate some times
	 * 
	 * @param k
	 */
	public void geneMutate(int k) {
		int ran1, ran2, temp;
		int count;
		count = random.nextInt(cityNum);
		for (int i = 0; i < count; i++) {
			ran1 = random.nextInt(cityNum);
			ran2 = random.nextInt(cityNum);
			while (ran1 == ran2) {
				ran2 = random.nextInt(cityNum);
			}
			temp = childGeneration[k][ran1];
			childGeneration[k][ran1] = childGeneration[k][ran2];
			childGeneration[k][ran2] = temp;
		}
	}

	/**
	 * the main function for GA algorithm
	 */
	public void run() {
		int i;
		int k;
		// initial the group
		initGroup();
		// calculate the initial fitness
		for (k = 0; k < M; k++) {
			fitness[k] = evaluate(parentGeneration[k]);
		}
		// calculate the range for choosing k th generation and store the
		// results in probability[max]
		calculateRange();

		for (int t = 0; t < total; t++) {
			evolution();
			// update the parent generation with the child generation
			for (k = 0; k < M; k++) {
				for (i = 0; i < cityNum; i++) {
					parentGeneration[k][i] = childGeneration[k][i];
				}
			}
			// calculate the new fitness
			for (k = 0; k < M; k++) {
				fitness[k] = evaluate(parentGeneration[k]);
			}
			// calculate the range for choosing k th generation and store the
			// results in probability[max]
			calculateRange();
		}
		System.out.println("minimum distance: " + lowestDistance);
		System.out.print("best path: ");
		for (i = 0; i < cityNum; i++) {
			System.out.print(bestPath[i] + " ");
		}
		System.out.println("start and end with " + bestPath[0] + " ");
	}

}

最后附一份测试代码(随机生成矩阵并测试)
本来是和回溯法以及分支限界法一起写的,这部分忽略就好
测试正确度的代码:

/**
 * 
 */
package test;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;

import branch_bounding.*;
import ga.GAalgorithm;
import backTrack.*;

/**
 * @author ly
 *
 */
public class TSPtest {

	public static Random random = new Random();

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		/**
		 * all the node number start with number 0 the unconnected city is
		 * presented by a enormous number
		 * 
		 */
		/**
		 * test the branch bounding
		 * testCaseNum是测试次数
		 */
		int testCaseNum = 14;

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

			System.out.println("====================" + i + "====================");
			int[][] path = testCase(testCaseNum, 100);
			System.out.println("=>Back Track");
			Recall r = new Recall(path, testCaseNum);
			r.run();
//			System.out.println("=>Branch Bounding");
//			BranchBoundingAlgorithm sp = new BranchBoundingAlgorithm(path, testCaseNum);
//			sp.run();
			System.out.println("=>GA");
			GAalgorithm ga = new GAalgorithm(500, 0.7f, 0.007f, path, testCaseNum);
			ga.run();
		}
	}

	/**
	 * 生成测试矩阵
	 * 
	 * @param n
	 *            矩阵规模
	 * @param maxn
	 *            矩阵最大元素
	 * @return 随机生成的测试矩阵
	 */
	public static int[][] testCase(int n, int maxn) {
		int[][] test = new int[n][n];
		for (int i = 0; i < n; i++) {
			for (int j = i; j < n; j++) {
				if (i == j)
					test[i][j] = 0;
				else {
					int a = 0;
					while (a <= 0) {
						a = random.nextInt(maxn);
					}
					test[i][j] = a;
				}
			}
		}
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < i; j++) {
				if (i == j)
					test[i][j] = 0;
				else {

					test[i][j] = test[j][i];
				}
			}
		}
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++) {
				System.out.printf("%-4s", test[i][j] + " ");
			}
			System.out.println();
		}
		return test;
	}

}

测试时间性能的代码:

/**
 * 
 */
package test;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;

import branch_bounding.*;
import ga.GAalgorithm;
import backTrack.*;

/**
 * @author ly
 *
 */
public class TSPPerformenceTest {
	public static Random random = new Random();
	public static int testCaseNum = 10;

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String order = "";
		System.out.println("please choose from BackTrack, BranchBounding, GA, quit");
		while (true) {
			try {
				order = br.readLine();
				switch (order) {
				case "BackTrack":
					testBackTrack();
					break;
				case "BranchBounding":
					testBranchBounding();
					break;
				case "GA":
					testGA();
					break;
				case "quit":
					System.exit(0);
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}

	}

	/**
	 * 测试GA
	 */
	private static void testGA() {
		// TODO Auto-generated method stub
		double sum = 0;
		double start;
		double end;
		double currenttime;
		for (int i = 5; i <= 20; i = i + 3) {
			System.out.println("############## matrix scale: " + i + " ##################");
			for (int j = 0; j < testCaseNum; j++) {
				System.out.println("====================" + j + "====================");
				int[][] path = testCase(i, 100);
				System.out.println("=>GA");

				GAalgorithm ga = new GAalgorithm(100000, 0.9f, 0.9f, path, i);
				start = System.currentTimeMillis();
				ga.run();
				end = System.currentTimeMillis();
				currenttime = end - start;
				sum += currenttime;
				System.out.println("time spent: " + currenttime);
			}
			sum = sum / testCaseNum;
			System.out.println("matrix scale: " + i + " average time: " + sum);
			sum = 0;

		}
	}

	/**
	 * 测试BranchBounding
	 */
	private static void testBranchBounding() {
		// TODO Auto-generated method stub
		double sum = 0;
		double start;
		double end;
		double currenttime;
		// i为矩阵规模
		for (int i = 5; i <= 20; i = i + 3) {
			System.out.println("############## matrix scale: " + i + " ##################");
			// j和testCaseNum都是表征每个规模的测试次数
			for (int j = 0; j < testCaseNum; j++) {
				System.out.println("====================" + j + "====================");
				int[][] path = testCase(i, 100);
				System.out.println("=>GA");

				BranchBoundingAlgorithm b = new BranchBoundingAlgorithm(path, i);
				start = System.currentTimeMillis();
				b.run();
				end = System.currentTimeMillis();
				currenttime = end - start;
				sum += currenttime;
				System.out.println("time spent: " + currenttime);
			}
			sum = sum / testCaseNum;
			System.out.println("matrix scale: " + i + " average time: " + sum);
			sum = 0;
		}
	}

	/**
	 * 测试BackTrack 代码结构同上
	 */
	private static void testBackTrack() {
		// TODO Auto-generated method stub
		double sum = 0;
		double start;
		double end;
		double currenttime;
		for (int i = 5; i <= 20; i = i + 3) {
			System.out.println("############## matrix scale: " + i + " ##################");
			for (int j = 0; j < testCaseNum; j++) {
				System.out.println("====================" + j + "====================");
				int[][] path = testCase(i, 100);
				System.out.println("=>GA");

				Recall r = new Recall(path, i);
				start = System.currentTimeMillis();
				r.run();
				end = System.currentTimeMillis();
				currenttime = end - start;
				sum += currenttime;
				System.out.println("time spent: " + currenttime);
			}
			sum = sum / testCaseNum;
			System.out.println("matrix scale: " + i + " average time: " + sum);
			sum = 0;
		}
	}

	/**
	 * 生成测试矩阵
	 * 
	 * @param n
	 *            矩阵规模
	 * @param maxn
	 *            矩阵最大元素
	 * @return 随机生成的测试矩阵
	 */
	public static int[][] testCase(int n, int maxn) {
		int[][] test = new int[n][n];
		for (int i = 0; i < n; i++) {
			for (int j = i; j < n; j++) {
				if (i == j)
					test[i][j] = 0;
				else {
					int a = 0;
					while (a <= 0) {
						a = random.nextInt(maxn);
					}
					test[i][j] = a;
				}
			}
		}
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < i; j++) {
				if (i == j)
					test[i][j] = 0;
				else {

					test[i][j] = test[j][i];
				}
			}
		}

		return test;
	}
}

你可能感兴趣的:(使用遗传算法求解TSP问题)