回溯法-详解旅行商问题(java)

回溯法-旅行商问题

问题:

某售货员要到若干城市去推销商品,已知各城市之间的路程。他要选定一条从驻地出发,经过每个城市一次,最后回到驻地的路线,使总的路程(或总旅费)最小。

问题分析:

现在我们从城市A出发,要去B,C,D,E共四个城市,按上面的顺序给城市编号1~5,每个城市用一个节点表示,可以直接到达的城市有连线,连线上的数字代表两个城市之间的路程(旅费),那么要去的城市地图就转换成了一个无向带权图。如图
在这里插入图片描述
在无向带权图G(V,E)中,节点代表城市,连线上的数字代表城市之间的路径长度,我们从1号节点出发,先走哪些景点,后走哪些城市呢?只要是可以直接到达的,即有边相连的,都是可以走的,问题就是要找出从出发地开始的一个城市排列,按照这个顺序旅行,不重复地走遍所以城市回到出发地,所经过的路径长度是最短的。
因此,问题的解空间是一颗排列树。显然,对于任何给定的一个无向带权图,存在某两个城市之间没有直接路径的情况。也就是说,并不是任何一个城市排列搜索一条可行路径(问题的可行解),因此需要设置约束条件,判断排列中相连的两个城市之间是否有边相连,有边的则可以走通;反之,是不可行路径,另外,在所有的可行路径中,要求找出一条最短路径,因此需要设置限界条件。

算法设计

(1)定义问题的解空间
旅行商问题解的形式为n元组:{x1,x2,…xi…xn},分量xi表示第i个要去的城市编号,城市的集合为S={1,2,3…n}。因为城市不可重复走,因此在确定xi时,前面走过的城市{x1,x2…xi-1}不可能再走,xi的取值为S-{x1,x2…xi-1},i=1,2,3…,n。
(2)解空间的组织结构
问题解空间是一颗排列树,树的深度为n=5。如图
在这里插入图片描述

(3)搜索解空间
约束条件
用二维数组g[][]存储无向带权图的邻接矩阵,如果g[i][j]不等于∞表示城市i和城市j有边相连,能走通。
限界条件
cl<bestl,cl的初始值为0,bestl的初始值为+∞。
cl:当前已经走过的城市所用的路径长度
bestl:表示当前找到的最短路径的路径长度。
搜索过程
扩展节点沿着某个分支扩展时需要判断约束条件和限界条件,如果满足,则进入深一层继续搜索;如果不满足,则剪掉该分支。搜索到叶子节点时,即找到当前最优解。搜索直到全部的活结点变成死结点为止。
搜索过程

详细过程请看陈小玉老师的《趣学算法》

代码

import java.util.Scanner;
public class Main {
    static int INF=(int)1e7;//设置无穷大的值为10的七次方
    static int N=100;
    static int [][]g=new int[N][N];//地图的无向带权邻接矩阵
    static int []x=new int[N];//记录当前路径
    static int []bestx=new int[N];//记录当前最优路径
    static int cl;//当前路径长度
    static int bestl;//当前最短路径长度
    static int n,m;//城市个数n,边数m
    static void swap(int array[], int a, int b) {//交换函数
        int temp;
        temp = array[a];
        array[a] = array[b];
        array[b] = temp;
    }
    static void Traveling(int t) {
        if (t > n) {//到达叶子节点
            /*
            推销货物的最后一个城市与住地城市有边相连并且路径长度比当前最优值小,说明找到了一条更好的路径,记录相关信息
             */
            if (g[x[n]][1] != INF && (cl + g[x[n]][1] < bestl)) {
                for (int j = 1; j <= n; j++) {
                    bestx[j] = x[j];
                }
                bestl = cl + g[x[n]][1];
            }
        } else {//没有到达叶子节点
            for (int j = t; j <= n; j++) {//搜索扩展节点的所有分支
                if (g[x[t - 1]][x[j]] != INF && (cl + g[x[t - 1]][x[j]] < bestl)) {//如果第t-1个城市与第t个城市有边相连并且有可能得到更短的路线
                    swap(x, t, j);//交换两个元素的值
                    cl = cl + g[x[t - 1]][x[t]];
                    Traveling(t+1);//从第t+1层的扩展结点继续搜索
                    //第t+1层搜索完毕,回溯到第t层
                    cl=cl-g[x[t-1]][x[t]];
                    swap(x,t,j);
                }
            }
        }
    }
    //初始化函数
    static void init() {
        bestl = INF;
        cl = 0;
        for (int i = 1; i <= n; i++)
            for (int j = i; j <= n; j++)
                g[i][j] = g[j][i] = INF;
        for (int i = 0; i <= n; i++) {
            x[i] = i;
            bestx[i] = 0;
        }
    }
    static void print(){
        System.out.print("最短路径");
        for (int i=1;i<=n;i++){
            System.out.print(bestx[i]+"---->");
        }
        System.out.println("1");
        System.out.print("最短路径长度:"+bestl);
    }

    public static void main(String[] args) {
    Scanner sc=new Scanner(System.in);
    int u,v,w;//u,v代表城市,w代表城市u,v之间的距离。
        System.out.println("请输入城市数n:");
        n=sc.nextInt();
        init();
        System.out.println("请输入城市之间的连线数:");
        m=sc.nextInt();
        System.out.println("请依次输入两个城市u,v以及之间的距离w:");
        for (int i=1;i<=m;i++){
            u=sc.nextInt();
            v=sc.nextInt();
            w=sc.nextInt();
            g[u][v]=g[v][u]=w;
        }
        Traveling(2);//结合排列树的图,从第二层开始
        print();
    }
}

运行示例

在这里插入图片描述

  • 26
    点赞
  • 117
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
旅行商问题(TSP)是一个著名的NP难问题,是求解所有城市之间的最短路径的问题。其实现方式有很多种,这里简单介绍一下基于遗传算法(GA)的实现方式。 下面是一个简单的Java代码示例,使用遗传算法求解旅行商问题: ``` import java.util.Arrays; import java.util.Random; public class TSPGA { private int[][] distance; // 城市之间的距离 private int cityNum; // 城市数量 private int populationSize; // 种群规模 private int maxGenerations; // 最大进化代数 private double crossoverProbability; // 交叉概率 private double mutationProbability; // 变异概率 private int elitismCount; // 精英个数 private int[] bestTour; // 最优路径 private int bestTourLength; // 最优路径长度 public TSPGA(int[][] distance, int populationSize, int maxGenerations, double crossoverProbability, double mutationProbability, int elitismCount) { this.distance = distance; this.cityNum = distance.length; this.populationSize = populationSize; this.maxGenerations = maxGenerations; this.crossoverProbability = crossoverProbability; this.mutationProbability = mutationProbability; this.elitismCount = elitismCount; } public void solve() { Population population = new Population(populationSize, cityNum); population.initialize(); for (int i = 0; i < maxGenerations; i++) { population = evolvePopulation(population); } bestTour = population.getFittest().getTour(); bestTourLength = population.getFittest().getTourLength(); } private Population evolvePopulation(Population population) { Population newPopulation = new Population(populationSize, cityNum); for (int i = 0; i < elitismCount; i++) { newPopulation.setIndividual(i, population.getFittest()); } for (int i = elitismCount; i < populationSize; i++) { Individual parent1 = selection(population); Individual parent2 = selection(population); Individual child = crossover(parent1, parent2); mutate(child); newPopulation.setIndividual(i, child); } return newPopulation; } private Individual selection(Population population) { Random rand = new Random(); Population tournament = new Population(elitismCount, cityNum); for (int i = 0; i < elitismCount; i++) { tournament.setIndividual(i, population.getIndividual(rand.nextInt(populationSize))); } return tournament.getFittest(); } private Individual crossover(Individual parent1, Individual parent2) { Individual child = new Individual(cityNum); int startPos = (int) (Math.random() * parent1.getTourLength()); int endPos = (int) (Math.random() * parent1.getTourLength()); for (int i = 0; i < child.getTourLength(); i++) { if (startPos < endPos && i > startPos && i < endPos) { child.setCity(i, parent1.getCity(i)); } else if (startPos > endPos) { if (!(i < startPos && i > endPos)) { child.setCity(i, parent1.getCity(i)); } } } for (int i = 0; i < parent2.getTourLength(); i++) { if (!child.containsCity(parent2.getCity(i))) { for (int j = 0; j < child.getTourLength(); j++) { if (child.getCity(j) == -1) { child.setCity(j, parent2.getCity(i)); break; } } } } return child; } private void mutate(Individual individual) { Random rand = new Random(); for (int i = 0; i < individual.getTourLength(); i++) { if (Math.random() < mutationProbability) { int j = rand.nextInt(individual.getTourLength()); int temp = individual.getCity(i); individual.setCity(i, individual.getCity(j)); individual.setCity(j, temp); } } } public int[] getBestTour() { return bestTour; } public int getBestTourLength() { return bestTourLength; } public static void main(String[] args) { int[][] distance = {{0, 2, 9, 10}, {1, 0, 6, 4}, {15, 7, 0, 8}, {6, 3, 12, 0}}; TSPGA tspGA = new TSPGA(distance, 100, 1000, 0.9, 0.1, 2); tspGA.solve(); System.out.println("Best tour length: " + tspGA.getBestTourLength()); System.out.println("Best tour: " + Arrays.toString(tspGA.getBestTour())); } } class Population { private Individual[] individuals; public Population(int populationSize, int tourSize) { individuals = new Individual[populationSize]; for (int i = 0; i < populationSize; i++) { individuals[i] = new Individual(tourSize); } } public void initialize() { for (int i = 0; i < individuals.length; i++) { individuals[i].generateIndividual(); } } public Individual getFittest() { Individual fittest = individuals; for (int i = 1; i < individuals.length; i++) { if (fittest.getFitness() <= individuals[i].getFitness()) { fittest = individuals[i]; } } return fittest; } public void setIndividual(int index, Individual individual) { individuals[index] = individual; } public Individual getIndividual(int index) { return individuals[index]; } } class Individual { private int[] tour; private int tourLength; public Individual(int tourSize) { tour = new int[tourSize]; tourLength = tourSize; } public void generateIndividual() { for (int i = 0; i < tourLength; i++) { tour[i] = i; } shuffle(); } private void shuffle() { Random rand = new Random(); for (int i = tourLength - 1; i > 0; i--) { int j = rand.nextInt(i + 1); int temp = tour[i]; tour[i] = tour[j]; tour[j] = temp; } } public int getFitness() { int fitness = 0; for (int i = 0; i < tourLength - 1; i++) { fitness += distance[tour[i]][tour[i + 1]]; } fitness += distance[tour[tourLength - 1]][tour]; return fitness; } public boolean containsCity(int city) { for (int i = 0; i < tourLength; i++) { if (tour[i] == city) { return true; } } return false; } public void setCity(int index, int city) { tour[index] = city; } public int getCity(int index) { return tour[index]; } public int getTourLength() { return tourLength; } public int[] getTour() { return tour; } } ``` 请问你还有什么其他问题吗?

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值