基于爬山算法求解TSP问题(JAVA)

基于爬山算法求解TSP问题(JAVA)一 TSP 问题 TSP 问题 TravellingSa 即旅行商问题 又译为旅行推销员问题 货郎担问题 是数学领域中著名问题之一 假设有一个旅行商人要拜访 n 个城市 他必须选择所要走的路径 路径的限制是每个城市只能拜访一次 而且最后要回到原来出发的城市 路径的选择目标是要求得的路径路程为所有路径之中的最小值 TSP 问题是一个组合优化问题 该问题可以被证明具有 NP

一、TSP问题


TSP问题(Travelling Salesman Problem)即旅行商问题,又译为旅行推销员问题、货郎担问题,是数学领域中著名问题之一。假设有一个旅行商人要拜访n个城市,他必须选择所要走的路径,路径的限制是每个城市只能拜访一次,而且最后要回到原来出发的城市。路径的选择目标是要求得的路径路程为所有路径之中的最小值。

TSP问题是一个组合优化问题。该问题可以被证明具有NPC计算复杂性。TSP问题可以分为两类,一类是对称TSP问题(Symmetric TSP),另一类是非对称问题(Asymmetric TSP)。所有的TSP问题都可以用一个图(Graph)来描述:

V={c1, c2, …, ci, …, cn},i = 1,2, …, n,是所有城市的集合. ci表示第i个城市, n为城市的数目;

E={(r, s): r,s∈ V}是所有城市之间连接的集合;

C = {crs: r,s∈ V}是所有城市之间连接的成本度量(一般为城市之间的距离);

如果crs = csr, 那么该TSP问题为对称的,否则为非对称的。

一个TSP问题可以表达为:

求解遍历图G = (V, E, C),所有的节点一次并且回到起始节点,使得连接这些节点的路径成本最低。

二、爬山算法

爬山算法是一种局部择优的方法,采用启发式方法,是对深度优先搜索的一种改进,它利用反馈信息帮助生成解的决策。 该算法每次从当前解的临近解空间中选择一个最优解作为当前解,直到达到一个局部最优解。属于人工智能算法的一种。

爬山算法实现很简单,其主要缺点是会陷入局部最优解,而不一定能搜索到全局最优解。如下图所示:假设C点为当前解,爬山算法搜索到A点这个局部最优解就会停止搜索,因为在A点无论向那个方向小幅度移动都不能得到更优的解。

基于爬山算法求解TSP问题(JAVA)

爬山算法实施步骤:

基于爬山算法求解TSP问题(JAVA)


三、爬山算法求解TSP问题

在该JAVA实现中我们选择使用tsplib上的数据att48,这是一个对称TSP问题,城市规模为48,其最优值为10628.其距离计算方法下图所示:

基于爬山算法求解TSP问题(JAVA)

具体代码如下:

package noah; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.util.Random; public class HillClimbing { private int MAX_GEN;// 迭代次数 private int cityNum; // 城市数量,编码长度 private int[][] distance; // 距离矩阵 private int bestT;// 最佳出现代数 private int[] bestGh;// 最好的路径编码 private int bestEvaluation; private Random random; public HillClimbing() { } / * constructor of GA * * @param n * 城市数量 * @param g * 运行代数 * / public HillClimbing(int n, int g) { cityNum = n; MAX_GEN = g; } // 给编译器一条指令,告诉它对被批注的代码元素内部的某些警告保持静默 @SuppressWarnings("resource") / * 初始化HillClimbing算法类 * @param filename 数据文件名,该文件存储所有城市节点坐标数据 * @throws IOException */ private void init(String filename) throws IOException { // 读取数据 int[] x; int[] y; String strbuff; BufferedReader data = new BufferedReader(new InputStreamReader( new FileInputStream(filename))); distance = new int[cityNum][cityNum]; x = new int[cityNum]; y = new int[cityNum]; for (int i = 0; i < cityNum; i++) { // 读取一行数据,数据格式1 6734 1453 strbuff = data.readLine(); // 字符分割 String[] strcol = strbuff.split(" "); x[i] = Integer.valueOf(strcol[1]);// x坐标 y[i] = Integer.valueOf(strcol[2]);// y坐标 } // 计算距离矩阵 // 针对具体问题,距离计算方法也不一样, // 此处用的是att48作为案例,它有48个城市,距离计算方法为伪欧氏距离,最优值为10628 for (int i = 0; i < cityNum - 1; i++) { distance[i][i] = 0; // 对角线为0 for (int j = i + 1; j < cityNum; j++) { double rij = Math .sqrt(((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j])) / 10.0); // 四舍五入,取整 int tij = (int) Math.round(rij); if (tij < rij) { distance[i][j] = tij + 1; distance[j][i] = distance[i][j]; } else { distance[i][j] = tij; distance[j][i] = distance[i][j]; } } } distance[cityNum - 1][cityNum - 1] = 0; bestGh = new int[cityNum]; bestEvaluation = Integer.MAX_VALUE; bestT = 0; random = new Random(System.currentTimeMillis()); } // 初始化编码Ghh void initGroup() { int i, j; bestGh[0] = random.nextInt(65535) % cityNum; for (i = 1; i < cityNum;)// 编码长度 { bestGh[i] = random.nextInt(65535) % cityNum; for (j = 0; j < i; j++) { if (bestGh[i] == bestGh[j]) { break; } } if (j == i) { i++; } } } public int evaluate(int[] chr) { int len = 0; // 染色体,起始城市,城市1,城市2...城市n for (int i = 1; i < cityNum; i++) { len += distance[chr[i - 1]][chr[i]]; } // 城市n,起始城市 len += distance[chr[cityNum - 1]][chr[0]]; return len; } // 爬山算法 public void pashan(int[] Gh, int T) { int i, temp, tt = 0; int ran1, ran2; int e;// 评价新值 int[] tempGh = new int[cityNum]; bestEvaluation = evaluate(Gh); // 爬山代数T for (tt = 0; tt < T; tt++) { for (i = 0; i < cityNum; i++) { tempGh[i] = Gh[i]; } ran1 = random.nextInt(65535) % cityNum; ran2 = random.nextInt(65535) % cityNum; while (ran1 == ran2) { ran2 = random.nextInt(65535) % cityNum; } // 两交换法实施邻域操作 temp = tempGh[ran1]; tempGh[ran1] = tempGh[ran2]; tempGh[ran2] = temp; e = evaluate(tempGh);// 评价新值 if (e < bestEvaluation) { bestT = tt; bestEvaluation = e; for (i = 0; i < cityNum; i++) { Gh[i] = tempGh[i]; } } } } public void solve() { initGroup();// 初始化编码 pashan(bestGh, MAX_GEN); System.out.println("最佳长度出现代数:"); System.out.println(bestT); System.out.println("最佳长度"); System.out.println(bestEvaluation); System.out.println("最佳路径:"); for (int i = 0; i < cityNum; i++) { System.out.print(bestGh[i] + ","); if (i % 10 == 0 && i != 0) { System.out.println(); } } } / * @param args * @throws IOException */ public static void main(String[] args) throws IOException { System.out.println("Start...."); HillClimbing hillClimbing = new HillClimbing(48, 5000); hillClimbing.init("c://data.txt"); hillClimbing.solve(); } } 

运行结果截图:

基于爬山算法求解TSP问题(JAVA)

四、总结

爬山算法由于其简单的结构,在处理多约束大规模问题时比较力不从心,很难得到较好的解,但在小规模的NP问题求解中,解的质量还是比较好的;此外爬山算法结构简单,在某些情况下,整体效率比A星算法的效果还好。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/205661.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月19日 下午5:29
下一篇 2026年3月19日 下午5:30


相关推荐

  • Pycharm配置Pyqt5(精细版)[通俗易懂]

    Pycharm配置Pyqt5(精细版)[通俗易懂]Pycharm配置Pyqt5(精细版)前言最近入手了一些关于Qt的项目开发,需要用到Pycharm与Pyqt5的一个结合,当然在安装时也是有一些小坑的,下面我来为大家分享一下在Pycharm中配置Pyqt5的过程。环境配置1、创建虚拟环境:condacreate-nmy_pyqtpython=x.x命令创建python版本为x.x(本人用的3.7)、名字为my_pyqt的虚拟环境。my_pyqt文件可以在Anaconda安装目录envs文件下找到。2、切换/激活虚拟环境:conda

    2022年8月29日
    5
  • OpenClaw 安装与配置全教程(Ubuntu 全新虚拟机版)

    OpenClaw 安装与配置全教程(Ubuntu 全新虚拟机版)

    2026年3月13日
    5
  • 强制删除文件 强制删除文件夹

    强制删除文件 强制删除文件夹
    在桌面新建一个txt文本打开这个txt文本,输入下面两行内容:
    del/f/s/q//?/%1
    rd /s/q//?/%1
    然后文件->另存为
    重新命名文件名为del.bat,并选择文件类型为“所以文件”,最后保存文件 
    一定要记着文件的位置了把要删除的文件拖到这个批处理del.bat上文件就静悄悄的删除了^-^

    2022年5月30日
    34
  • linux搭建开源ldap服务器方法

    linux搭建开源ldap服务器方法1.什么是ldap服务器ldap是统一认证服务,它的优点是存储用户认证等不经常改变的信息,有清晰的组织结构。ldap条目概念:基准DN,例如dc=company,dc=com,DN,例如cn=test,dc=company,dc=com,一个DN就是一个条目,RDN是相对DN,具有唯一性,上面例子的DN的RDN就是cn=test2.下载openldapopenld…

    2022年5月15日
    44
  • GridLayout 使用总结「建议收藏」

    GridLayout 使用总结「建议收藏」一、简介GridLayout是Android4.0引入的网格布局,使用它可以减少布局嵌套。也算是常用,但一直没仔细看过,今天研究一下二、常用属性介绍GridLayout使用属性属性作用android:columnCount最大列数android:rowCount最大行数android:orientationGr…

    2022年6月14日
    30
  • 可变形卷积网络:计算机新“视”界

    可变形卷积网络:计算机新“视”界卷积核的形状可以是变化的 变形的卷积核能让它只看感兴趣的图像区域 这样识别出来的特征更佳

    2026年3月16日
    3

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号