贪心算法:旅行商问题(TSP)

TSP问题(Traveling Salesman Problem,旅行商问题),由威廉哈密顿爵士和英国数学家克克曼T.P.Kirkman于19世纪初提出。问题描述如下:
有若干个城市,任何两个城市之间的距离都是确定的,现要求一旅行商从某城市出发必须经过每一个城市且只在一个城市逗留一次,最后回到出发的城市,问如何事先确定一条最短的线路已保证其旅行的费用最少?

另一个类似的问题为:一个邮递员从邮局出发,到所辖街道投邮件,最后返回邮局,如果他必须走遍所辖的每条街道至少一次,那么他应该如何选择投递路线,使所走的路程最短?这个描述之所以称为中国邮递员问题(Chinese Postman Problem CPP)

为简化该问题,假设只有A、B、C、D四个城市,各城市的关系如图所示,权值表示两个城市之间的的距离。
这里写图片描述
为了将图中关系数据化,可用如下规则来描述:

城市映射为编号:A——0,B——1,C——2,D——3;
城市之间的距离用二维数组来表示,记为D[i][j],如:D[0][1]表示城市A与城市B之间的距离,于是D[0][1]=2;
用一维数组S[i]来存储访问过的路径。

该问题的基本解法为递归遍历,但是会产生组合爆炸问题(时间复杂度为n!),此处不做介绍,而引入一种更为高效的解法:贪心算法。该算法描述如下:

贪心算法:又称贪婪算法(greedy algorithm),该算法是指:在对问题求解时,总是做出当前情况下的最好选择,否则将来可能会后悔,故名“贪心”。这是一种算法策略,每次选择得到的都是局部最优解。选择的策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。
针对TSP问题,使用贪心算法的求解的过程为:
1.从某一个城市开始,每次选择一个城市,直到所有的城市被走完。
2.每次在选择下一个城市的时候,只考虑当前情况,保证迄今为止经过的路径总距离最小。

使用贪心算法求解TSP问题的步骤描述如图所示:
这里写图片描述这里写图片描述这里写图片描述

具体代码如下:

#include<iostream>
using namespace std;
#define n 4
int main()
{
    int i,j,k,l;
    int S[n];//用于存储已访问过的城市
    int D[n][n];//用于存储两个城市之间的距离
    int sum = 0;//用于记算已访问过的城市的最小路径长度
    int Dtemp;//保证Dtemp比任意两个城市之间的距离都大(其实在算法描述中更准确的应为无穷大)
    int flag;最为访问的标志,若被访问过则为1,从未被访问过则为0
    /*初始化*/
    i = 1;//i是至今已访问过的城市
    S[0] = 0;
    D[0][1] = 2;D[0][2] = 6;D[0][3] = 5;D[1][0] = 2;D[1][2] = 4;
    D[1][3] = 4;D[2][0] = 6;D[2][1] = 4;D[2][3] = 2;D[3][0] = 5;
    D[3][1] = 4;D[3][2] = 2;
    do{
        k = 1;Dtemp = 10000;
        do{
            l = 0;flag = 0;
            do{
                if(S[l] == k){//判断该城市是否已被访问过,若被访问过,
                    flag = 1;//则flag为1
                    break;//跳出循环,不参与距离的比较
                }else
                    l++;
            }while(l < i);
            if(flag == 0&&D[k][S[i - 1]] < Dtemp){/*D[k][S[i - 1]]表示当前未被访问的城市k与上一个已访问过的城市i-1之间的距离*/
                j = k;//j用于存储已访问过的城市k
                Dtemp = D[k][S[i - 1]];//Dtemp用于暂时存储当前最小路径的值
            }
            k++;
        }while(k < n);
        S[i] = j;//将已访问过的城市j存入到S[i]中
        i++;
        sum += Dtemp;//求出各城市之间的最短距离,注意:在结束循环时,该旅行商尚未回到原出发的城市
    }while(i < n);
    sum += D[0][j];//D[0][j]为旅行商所在的最后一个城市与原出发的城市之间的距离
    for(j = 0; j < n; j++){ //输出经过的城市的路径
        cout<<j<<" ";
    }
    cout<<"\n"<<sum;//求出最短路径的值
}

运行结果如下图所示:
这里写图片描述

参考资料:《计算机导论》第7讲-算法-程序与计算系统之灵魂

TSP(Traveling Salesman Problem,旅行商问题)是一个经典的组合优化问题,目标是找到一条经过所有城市且路径最短的路线。贪心算法是一种常用的解决TSP问题的方法。 TSP问题的贪心算法思路如下:首先选择一个起始城市,然后每次选择距离当前城市最近且未被访问过的城市作为下一个要访问的城市,直到所有城市都被访问过,最后回到起始城市形成闭环。 使用Python实现TSP问题的贪心算法可以按照以下步骤进行: 1. 首先创建一个n x n的距离矩阵,其中n为城市数量,矩阵每个元素表示城市之间的距离。 2. 初始化一个记录已访问城市的列表visited,起始城市设置为已访问。 3. 初始化一个空的路径列表path,将起始城市添加到路径。 4. 从起始城市开始,依次遍历每个城市,选择距离当前城市最近的未访问城市,将其添加到路径中,并将该城市标记为已访问。 5. 重复步骤4,直到所有城市都被访问过。 6. 计算路径长度,即遍历路径列表中的城市并累加对应的距离矩阵元素。 7. 将最后一个城市与起始城市形成闭环,计算闭环长度。 8. 返回路径和闭环长度作为结果。 以下是Python代码实现TSP问题的贪心算法: ```python import numpy as np def tsp_greedy(distance_matrix): n = len(distance_matrix) visited = [0] * n # 记录已访问的城市 visited[0] = 1 # 设置起始城市为已访问 path = [0] # 路径列表,开始时只包含起始城市 current_city = 0 # 当前城市为起始城市 while len(path) < n: closest_city = -1 # 距离当前城市最近的未访问城市 min_dist = float('inf') # 最短距离 for i in range(n): if visited[i] == 0 and distance_matrix[current_city][i] < min_dist: closest_city = i min_dist = distance_matrix[current_city][i] path.append(closest_city) # 将最近城市添加到路径中 visited[closest_city] = 1 # 标记最近城市为已访问 current_city = closest_city # 更新当前城市 path_length = sum(distance_matrix[path[i-1]][path[i]] for i in range(1, n)) # 计算路径长度 cyclic_length = path_length + distance_matrix[path[-1]][path[0]] # 计算闭环长度 return path, cyclic_length # 距离矩阵示例 distance_matrix = np.array([[0, 1, 2, 3], [1, 0, 4, 5], [2, 4, 0, 6], [3, 5, 6, 0]]) path, cyclic_length = tsp_greedy(distance_matrix) print("最短路径:", path) print("最短路径长度:", cyclic_length) ``` 以上是使用贪心算法解决TSP问题的简单示例,将根据距离矩阵计算出最短路径和最短路径长度。实际应用中,可能需要对贪心算法进行改进和优化,以得到更好的解。 注意:以上代码仅作为示例,具体实现还需要根据实际问题进行适当的调整。
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值