旅行商问题(全排列方法)

一、题目

  • 一个售货员必须访问n个城市,恰好访问每个城市一次,并最终回到出发城市。
    售货员从城市i到城市j的旅行费用是一个整数,旅行所需的全部费用是他旅行经过的的各边费用之和,而售货员希望使整个旅行费用最低。
  • (等价于求图的最短哈密尔顿回路问题)令G=(V, E)是一个带权重的有向图,顶点集V=(v0, v1, ..., vn-1)。从图中任一顶点vi出发,经图中所有其他顶点一次且只有一次,最后回到同一顶点vi的最短路径。

二、解题思路

此问题我们可以用全排列问题解决,全排列问题详见此篇文章。全排列就是枚举各个城市的全排列组合,但是必要时通过剪枝的方法求解,在交换时如果发现两个城市之间距离为无穷大,则可剔除此次无效排列。但是为了减少枚举数量,我们第一个城市将不参与全排列,所以枚举数量减少了\frac{1}{n}

三、测试用例

 

其中1,2,3,4,5代表五个城市。此模型可抽象为图,可用邻接矩阵表示,如下图所示:

四、代码

#include <iostream>

#define N 6
#define INF 10e7

using namespace std;
//定义邻接矩阵表示图模型
int g[N][N]= {{-1,-1,-1,-1,-1,-1},
              {-1,INF,3,INF,8,9},
              {-1,3,INF,3,10,5},
              {-1,INF,3,INF,4,3},
              {-1,8,10,4,INF,20},
              {-1,9,5,3,20,INF}};
//保存路径的最小值
int minLength = INF;
//当前路径的长度
int currentLength = 0 ;
//保存路径
int path[N] = {0};
//保存城市编号
int city[N] = {-1,1,2,3,4,5};
//城市个数
int length = N -1;
//交换数组的两个数,参数为数组索引
void swap(int s,int t){
    int temp = city[t];
    city[t] = city[s];
    city[s] = temp;
}
//index表示从第index开始,计算index到n的的全排列,
//即dfs(1)代表从第一数算起,生成1-n的全排列
void dfs(int index){
    if(index > length){
        //如果最后一个城市到第一个城市不是无穷大,
        //并且是当前的最短路径,则保存新路径和最短路径
        if(g[city[length]][city[1]] != INF && (currentLength+g[city[length]][city[1]] < minLength)){
            for(int i=1 ; i <= length ;i++){
                path[i] = city[i];
            }
            minLength = currentLength + g[city[length]][city[1]];
        }
        return;
    }
    else{
        for(int i = index ; i <= length ;i++){
            if(g[city[i]][city[index-1]] != INF && (currentLength + g[city[i]][city[index-1]] < minLength)){
                swap(i,index);
                currentLength += g[city[index]][city[index-1]];
                //继续生成index+1到n的全排列
                dfs(index+1);
                currentLength -= g[city[index]][city[index-1]];
                //回溯时交换回来
                swap(i,index);
            }
        }
    }
}
//打印路径
void print(){
    cout<<"最短路径: ";
    for(int i=1;i<=length;i++){
        cout<<path[i]<<"--->";
    }
    cout<<city[1]<<endl;
    cout<<"最短路径长度:"<<minLength;
}

int main()
{
    dfs(2);
    print();
    return 0;
}

五、 运行结果及分析

  • 时间复杂度:O(n!)
  • 空间复杂度:O(n)

本次算法只是暴力求法,旅行商问题也可以用动态规划算法来解决,具体 详看我的另一篇文章。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值