旅行商问题(TSP)概述

news/2024/10/12 1:34:21

旅行商问题(TSP)概述

1. TSP问题的复杂性

定义:旅行商问题(Traveling Salesman Problem, TSP)是给定一系列城市及其之间的距离,要求找到一条最短路径,使得旅行商从某个城市出发,经过每个城市恰好一次并返回到起点城市。

复杂性分析:

  • TSP是一个NP-hard问题,这意味着目前没有已知的多项式时间算法可以解决所有实例。
  • 随着城市数量的增加,可能的路径组合呈指数增长。例如,对于n个城市,可能的路径数为(n-1)!/2。
  • 因此,对于较小的城市数(通常n ≤ 20),可以使用暴力搜索或动态规划方法;对于较大的城市数,常用启发式或近似算法。

2. 贪心法的主要思路和求解步骤

贪心法简介:

贪心算法通过每一步选择中都采取当前状态下最好或最优的选择,从而希望得到全局最好或最优解。

求解步骤:

  • 初始化:选择一个起始城市作为当前城市,并将其标记为已访问。
  • 选择下一个城市:在未访问城市中选择与当前城市距离最短的城市,并移动到该城市。
  • 重复:继续选择下一个城市,直到所有城市都被访问过。
  • 返回起点:最后从最后一个城市返回起始城市,完成环路。

3. 两种贪心法求解TSP的近似算法

算法1:最近邻点算法

步骤:

  • 从起始城市出发,标记为已访问。
  • 在未访问的城市中选择距离当前城市最近的城市,并移动到该城市。
  • 重复步骤2,直到所有城市均已访问。
  • 返回起始城市。

上代码

#include<bits/stdc++.h> 
using namespace std;const int MAX = 10; // 最大城市数量
double dist[MAX][MAX]; // 城市距离矩阵
bool visited[MAX]; // 标记是否访问过// 找到最近的未访问城市
int findNearestCity(int current, int n) {double minDist = numeric_limits<double>::max();int nearestCity = -1;for (int i = 1; i <= n; ++i) {if (!visited[i] && dist[current][i] < minDist) {minDist = dist[current][i];nearestCity = i;}}return nearestCity;
}// 实现最近邻算法
vector<int> nearestNeighbor(int start, int n) {vector<int> path;fill(visited, visited + n, false);int current = start;visited[current] = true;path.push_back(current);for (int i = 1; i < n; ++i) {current = findNearestCity(current, n);visited[current] = true;path.push_back(current);}path.push_back(start); // 返回起点return path;
}int main() {int n;cin >> n;for (int i = 1; i <= n; ++i) {for (int j = 1; j <= n; ++j) {cin >> dist[i][j];}}vector<int> path = nearestNeighbor(1, n);cout << "最近邻算法路径: ";for (int city : path) {cout << city << " ";}cout << endl;return 0;
}

算法2:贪婪插入算法

步骤:

  • 初始化一个路径,包括任意两个城市。
  • 每次从未访问城市中选择一个城市,插入到当前路径中的最佳位置,以使得路径长度最小。
  • 重复步骤2,直到所有城市均已访问。
  • 返回起始城市。

上代码

#include<bits/stdc++.h> 
using namespace std;vector<int> greedyInsertTSP(const vector<vector<int>>& distanceMatrix) {int n = distanceMatrix.size();vector<bool> visited(n, false);vector<int> path;int currentCity = 0;visited[currentCity] = true;path.push_back(currentCity);for (int i = 1; i < n; ++i) {// 找到最近的未访问城市int nearestCity = -1;int minDistance = numeric_limits<int>::max();for (int j = 0; j < n; ++j) {if (!visited[j] && distanceMatrix[currentCity][j] < minDistance) {minDistance = distanceMatrix[currentCity][j];nearestCity = j;}}// 插入最近的城市到路径中path.push_back(nearestCity);visited[nearestCity] = true;currentCity = nearestCity;}// 完成循环,返回起始城市path.push_back(path[0]); // 返回到起始城市return path;
}int main() {int n;cin >> n;vector<vector<int>> distanceMatrix(n, vector<int>(n));for (int i = 0; i < n; ++i) {for (int j = 0; j < n; ++j) {cin >> distanceMatrix[i][j];}}vector<int> result = greedyInsertTSP(distanceMatrix);for (int city : result) {cout << city << " ";}cout << endl;return 0;
}

4. 解的对比分析

  • 效率:
    • 最近邻算法简单易实现,但可能会陷入局部最优。
    • 贪婪插入算法相对复杂一些,通常能提供更好的近似解,因为它考虑了整体路径的影响。
  • 解的质量:
    • 最近邻算法的路径通常较短,但不一定是最优解。
    • 贪婪插入算法通过插入策略,可以获得更接近实际最优解的路径。
  • 时间复杂度:
    • 最近邻算法的时间复杂度为O(n^2)。
    • 贪婪插入算法的时间复杂度为O(n^2),但由于需要查找最佳插入位置,实际时间可能略高于最近邻算法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/70465.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

Design Compiler多时钟约束

这里的资料来源于《Synopsys Timing Constraints and Optimization User Guide, Version P-2019.03-SP4, September 2019》 下面图中这几种情况都是我在实际项目中碰到过的,因此有必要单独做个说明。 第一个是同步派生时钟,即CK2是通过CK1的分频来产生的,我们之前的一个实际…

uniapp创建小程序

uniapp创建小程序https://www.dcloud.io/一、安装Hbuilder和对应基本操作 ​ 安装Hbuilder这里就不在赘述。 (一)、插件安装: ​ 如果考虑到后续需要使用Scss,可以前往插件市场进行搜索安装,浏览器会提示我们是否需要打开对应的HbuilderX,然后进入应用进行安装。(二)…

labelme使用方法

labelme是一款在实例分割、语义分割、目标检测等任务中的一个常用工具,本文将介绍如何使用labelme。 labelme有各种版本,包括ubuntu、windows、macOS等。关于windows版本,也可以下载其相关的exe文件https://github.com/wkentaro/labelme/releases来使用标注 一、安装labelme…

《综合与Design Compiler》笔记

《综合与Design Compiler》笔记 一直没系统的整理过DC这块的东西,这里借助一个挺好的文档《综合与Deisgn Compiler》以及我自己的经验和理解来归总一下。 1. 综合是什么 综合是使用软件的方法来设计硬件,然后将门级电路实现与优化的工作留给综合工具的一种设计方法。它是根据…

C# unsafe 快速复制数组

/// <summary>/// 复制内存/// </summary>/// <param name="dest">目标指针位置</param>/// <param name="src">源指针位置</param>/// <param name="count">字节长度</param>/// <returns&…

11.Java集合框架_Set接口

Set接口和常用方法 基本介绍无序(添加和取出的顺序不一致),没有索引。 不允许重复元素,所以最多包含一个null。 JDK API中Set接口的实现类有HashSet、LinkedHashSet和TreeSet。set接口常用方法 和List接口一样,set接口也是Collection的子接口,因此,常用方法和Collection…

罗技鼠标永久宏定义设置

背景 写程序用到最多的组合按键就是ctrl+c, ctrl+v, 而这些能不能在鼠标上实现,这样就能解放左手了(机智如我) 硬件 需要一款支持宏定义的鼠标,而罗技系列正好拥有(未收广告费),目前尝试在g102, g304, gpwer代上都可运行 思路 使用ghub软件定义宏后加载到鼠标的板载内存上遇…