Java旅行商问题知识点(含面试大厂题和源码)

文章介绍了旅行商问题(TSP)的定义、作为组合优化问题的特性,以及解决方法如穷举搜索、动态规划、分支限界法和遗传算法。给出了Java实现的穷举搜索示例,并强调了在面试中TSP作为评估算法能力的工具。
摘要由CSDN通过智能技术生成

旅行商问题(Travelling Salesman Problem,简称TSP)是组合优化中的一个经典问题。问题的目标是找到最短可能的路径,让旅行商从一个城市出发,经过所有其他城市恰好一次,然后回到起始城市。

TSP是一个NP-hard问题,这意味着目前没有已知的多项式时间算法可以解决所有实例。尽管如此,对于小规模的问题,可以通过穷举搜索(Brute Force)或者启发式算法(如动态规划、分支限界、遗传算法等)找到精确解。对于大规模问题,通常采用近似算法或者启发式搜索来找到近似解。

穷举搜索(Brute Force)

穷举搜索是解决TSP问题的一种直接方法,它尝试所有可能的路径组合,然后选择总距离最短的一条。这种方法的时间复杂度是O(n!),因为旅行商需要访问每个城市的排列,其中n是城市的数量。

动态规划

对于TSP问题,动态规划方法通常使用held-karp算法,该算法通过将问题分解为子问题,并存储子问题的解来避免重复计算。held-karp算法的时间复杂度是O(n^2 * 2^n)。

分支限界法

分支限界法是一种在解空间树上进行搜索的算法,它通过剪枝来避免搜索整个解空间。这种方法可以找到近似解,并且在实际应用中非常有效。

遗传算法

遗传算法是一种启发式搜索算法,它模仿自然选择的过程来生成问题的解。遗传算法通过迭代地选择、交叉、变异和替换候选解来寻找最优解。

源码实现 - 穷举搜索(Java):

import java.util.*;

public class TSPBruteForce {
    private static final int INF = Integer.MAX_VALUE / 2;

    public static int tsp(int[][] distances, int n) {
        int[][] dp = new int[n][1 << n];
        int[] path = new int[1 << n];
        int result = INF;

        for (int i = 0; i < n; i++) {
            Arrays.fill(dp[i], INF);
            dp[i][1 << i] = 0;
            path[1 << i] = i;
        }

        for (int mask = 1; mask < (1 << n); mask++) {
            int lastCity = Integer.bitCount(mask) - 1;
            int currentCost = dp[lastCity][mask];

            if (currentCost >= result) continue;

            for (int nextCity = 0; nextCity < n; nextCity++) {
                if ((mask & (1 << nextCity)) == 0) {
                    int newMask = mask | (1 << nextCity);
                    int newPath[] = new int[newMask];
                    System.arraycopy(path, 0, newPath, 0, newMask - (1 << nextCity));
                    newPath[newMask - 1] = nextCity;
                    int newCost = currentCost + distances[path[newMask - (1 << nextCity)]][nextCity];
                    if (newCost < dp[nextCity][newMask]) {
                        dp[nextCity][newMask] = newCost;
                        path[newMask] = newPath;
                    }
                }
            }
        }

        for (int i = 0; i < n; i++) {
            result = Math.min(result, dp[i][(1 << n) - 1]);
        }

        return result;
    }

    public static void main(String[] args) {
        int[][] distances = {
            {0, 10, 15, 20},
            {10, 0, 35, 25},
            {15, 35, 0, 30},
            {20, 25, 30, 0}
        };
        int n = 4;
        int result = tsp(distances, n);
        System.out.println("Minimum cost of TSP: " + result);
    }
}

在面试中,TSP问题可以用来评估应聘者的算法设计能力和问题解决技巧。通过实现TSP问题的解决方案,可以展示你对组合优化问题的理解和算法的掌握程度。希望这些知识点和示例代码能够帮助你更好地准备面试!旅行商问题(TSP)是算法面试中的一个高级问题,通常出现在大厂的面试中,用于评估应聘者解决复杂问题的能力。以下是三道可能出现在大厂面试中的与旅行商问题相关的编程题目,以及相应的Java源码实现。

题目 1:简单的旅行商问题

描述
给定一个城市列表和每对城市之间的距离,找到访问每个城市一次并返回起点的最短路径。

示例

输入: 城市间距离矩阵如下:
[
  [0, 10, 15, 20],
  [10, 0, 35, 25],
  [15, 35, 0, 30],
  [20, 25, 30, 0]
]
输出: 最短路径的总距离

Java 源码(使用穷举搜索):

import java.util.Arrays;

public class SimpleTSP {
    public int shortestPath(int[][] distances) {
        int n = distances.length;
        int minDistance = Integer.MAX_VALUE;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (i != j) {
                    int[] path = new int[n];
                    int distance = 0;
                    path[0] = i;
                    for (int k = 0; k < n - 1; k++) {
                        distance += distances[path[k]][j];
                        path[k + 1] = j;
                        j = (k + 1) % n;
                    }
                    distance += distances[path[n - 1]][i];
                    if (distance < minDistance) {
                        minDistance = distance;
                    }
                }
            }
        }
        return minDistance;
    }

    public static void main(String[] args) {
        SimpleTSP solution = new SimpleTSP();
        int[][] distances = {
            {0, 10, 15, 20},
            {10, 0, 35, 25},
            {15, 35, 0, 30},
            {20, 25, 30, 0}
        };
        int result = solution.shortestPath(distances);
        System.out.println("Minimum distance of TSP: " + result);
    }
}

题目 2:近似旅行商问题

描述
给定一个城市列表和每对城市之间的距离,找到一个近似的最短路径,该路径访问每个城市一次并返回起点。

示例

输入: 城市间距离矩阵同上
输出: 近似最短路径的总距离

Java 源码(使用近似算法,如最小生成树):

import java.util.PriorityQueue;

public class ApproximateTSP {
    public int approximatePath(int[][] distances) {
        int n = distances.length;
        PriorityQueue<int[]> pq = new PriorityQueue<>(n, (a, b) -> (a[0] - b[0]));
        for (int i = 0; i < n; i++) {
            pq.offer(new int[]{distances[0][i], i});
        }
        int[] path = new int[n];
        int totalDistance = 0;
        for (int i = 0; i < n - 1; i++) {
            int[] edge = pq.poll();
            totalDistance += edge[0];
            path[i] = edge[1];
            if (i < n - 2) {
                for (int j = 0; j < n; j++) {
                    if (j != edge[1]) {
                        pq.offer(new int[]{distances[edge[1]][j] + distances[j][edge[1]], j});
                    }
                }
            }
        }
        totalDistance += distances[path[n - 2]][path[0]];
        return totalDistance;
    }

    public static void main(String[] args) {
        ApproximateTSP solution = new ApproximateTSP();
        int[][] distances = {
            {0, 10, 15, 20},
            {10, 0, 35, 25},
            {15, 35, 0, 30},
            {20, 25, 30, 0}
        };
        int result = solution.approximatePath(distances);
        System.out.println("Approximate minimum distance of TSP: " + result);
    }
}

题目 3:带时间窗口的旅行商问题

描述
给定一个城市列表、每对城市之间的距离,以及每个城市的时间窗口,找到访问每个城市一次并返回起点的最短路径,同时满足每个城市的时间窗口要求。

示例

输入: 城市间距离矩阵和时间窗口如下:
[
  [0, 10, 15, 20],
  [10, 0, 35, 25],
  [15, 35, 0, 30],
  [20, 25, 30, 0]
]
时间窗口:每个城市从0开始,持续24小时
输出: 满足时间窗口要求的最短路径的总距离

Java 源码(这个问题通常需要复杂的算法或启发式方法,这里提供一个简化的示例):

public class TimeWindowTSP {
    // 简化的示例,不考虑时间窗口的复杂性
    public int shortestPathWithTimeWindows(int[][] distances) {
        // 这里使用的是普通的穷举搜索,实际问题需要考虑时间窗口
        return shortestPath(distances);
    }

    // 调用之前的shortestPath方法
}

// 其他代码与之前的示例相同

这些题目和源码展示了旅行商问题的不同类型的问题以及如何在实际编程中解决它们。在面试中,能够根据问题的特点选择合适的算法并实现其解决方案是非常重要的。希望这些示例能够帮助你更好地准备面试!

  • 15
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
旅行商问题(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; } } ``` 请问你还有什么其他问吗?

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值