旅行售货员问题(回溯法、Java)

package com.ltcode.ds;

/**
 * @author LT
 * @github [https://github.com/ltcodes] [https://gitee.com/fltcode]
 * @date 2021/5/25 - 22:13
 * @description
 * 二.针对旅行售货员问题,写出问题分析、回溯法设计思想、步骤、代码实现过程,并进行总结分析
 */
public class CeShi52 {

    private static int n;//图G的顶点数
    private static int[] x;//当前解路径
    private static int[] bestx;//最优解路径
    private static int[][] a;//图G的邻接矩阵
    private static int cc;//当前路径x[1:i]的费用
    private static int bestc;//最优解费用
    private static int NoEdge = Integer.MAX_VALUE;//无边标记、最大值

    // 回溯算法
    public static void BackTrack(int i){
        if (i == n) {
            // 若点n-1和点n有连线且点1和n有连线且比最优路径短
            if (a[x[n-1]][x[n]] != NoEdge && a[x[n]][1] != NoEdge
                    && (cc + a[x[n - 1]][n] + a[x[n]][1] < bestc || bestc == NoEdge)) {
                for (int j = 1; j <= n; j++) {
                    // 将最优路径保存进bestx
                    bestx[j] = x[j];
                }
                // 最优值
                bestc = cc + a[x[n - 1]][x[n]] + a[x[n]][1];
            }
            return;
        }
        for (int j = i; j <= n; j++) {
            // 点i-1和点j是否存在路径且比最优路径短
            if (a[x[i - 1]][x[j]] != NoEdge && (cc + a[x[i - 1]][x[j]] < bestc || bestc == NoEdge)) {
                // 搜索子树
                swap(x, i, j);
                cc += a[x[i - 1]][x[i]];
                BackTrack(i+1);
                cc -= a[x[i - 1]][x[i]];
                swap(x, i, j);
            }
        }
    }

    public static void swap(int[] x, int i, int j){
        int temp = x[i];
        x[i] = x[j];
        x[j] = temp;
    }

    public static int tsp(int[] v){
        x = new int[n + 1];
        // 初始化
        for (int i = 1; i <= n; i++) {
            x[i] = i;
        }
        bestc = NoEdge;// 初始化设置最少花费为最大值
        bestx = v;// 最优路径为v
        cc = 0;// 当前花费为0
        BackTrack(2);// 从2开始搜索,搜索x[2:n]的全排列
        return bestc;
    }

    public static void main(String[] args) {
        // 测试数据
        n = 4;
        a = new int[][]{
                {0, 0, 0, 0, 0},
                {0, NoEdge, 30, 6, 4},
                {0, 30, NoEdge, 5, 10},
                {0, 6, 5, NoEdge, 20},
                {0, 4, 10, 20, NoEdge}
        };
        int[] v = new int[n + 1];
        int bestcc = tsp(v);
        System.out.println("最优费用为:" + bestcc);
        System.out.print("最优路径为:");
        for (int i = 1; i <= n; i++) {
            System.out.print(i == n ? bestx[i]:(bestx[i] + "->"));
        }
        /**
         * 运行结果
         * 最优费用为:25
         * 最优路径为:1->3->2->4
         */
    }

}

旅行售货员问题是一个经典的组合优化问题,它的目标是在给定一组城市以及每对城市之间的距离,到一条最短的路径,使得每个城市恰好被访问一次,并且最终回到起点城市。 回溯法是解决该问题的一种常见方法,其基本思想是从起点出发,逐步选择下一个城市,并计算当前路径的长度,直到遍历完所有城市后回到起点。在选择下一个城市时,需要满足两个条件:未被访问过且到当前城市的距离最短。 以下是一个简单的C语言实现旅行售货员问题回溯法代码,其中假设城市编号从0开始,距离由二维数组dist[][]表示: ``` #include <stdio.h> #define N 5 // 城市数量 int dist[N][N] = { // 城市间距离 {0, 10, 20, 30, 40}, {10, 0, 25, 35, 15}, {20, 25, 0, 45, 30}, {30, 35, 45, 0, 50}, {40, 15, 30, 50, 0} }; int path[N]; // 存储当前路径 int visited[N]; // 标记城市是否已访问 int min_dist = 0x7fffffff; // 最短路径长度 void tsp(int cur_city, int cur_dist, int cnt) { // cur_city:当前所在城市编号,cur_dist:当前路径长度,cnt:已访问城市数量 if (cnt == N) { // 遍历完所有城市 if (cur_dist + dist[cur_city] < min_dist) { // 如果形成一条更短的路径 min_dist = cur_dist + dist[cur_city]; // 更新最短路径长度 for (int i = 0; i < N; i++) { printf("%d -> ", path[i]); // 输出路径 } printf("%d\n", path); } return; } for (int i = 0; i < N; i++) { if (!visited[i]) { // 如果该城市未被访问 visited[i] = 1; // 标记为已访问 path[cnt] = i; // 存储路径 tsp(i, cur_dist + dist[cur_city][i], cnt + 1); // 继续遍历 visited[i] = 0; // 回溯 } } } int main() { path = 0; // 起点为城市0 visited = 1; // 标记起点已访问 tsp(0, 0, 1); // 从起点开始遍历 printf("最短路径长度为:%d\n", min_dist); return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值