求问TSP问题的多种算法解决

赫爾修羅-韋 2015-06-04 06:47:18
现在需要做一个TSP问题的解法,表示遇到了无奈的情况

问题描述:旅行商问题,已知N个城市的坐标或者距离邻接矩阵(int类型),从一个城市出发固定0城市或者固定1城市出发,经过且仅经过其余N-1个城市一次,回到出发城市。求最短距离,并且需要知道最短距离的途径路径。

测试样例:已知坐标的,最大有52个城市
已知距离邻接矩阵的,最大有58个城市

0、暴力法:城市顺序全排列,找到最短距离(纯属开玩笑,跑两天不知道行不行···
1、回溯法:运行了1个小时才能得到结果而且只是,表示未免也太慢了点吧。
2、分支定界法:空间消耗太大了,运行时间也难以保证。
3、动态规划法:空间复杂度要求太高了,城市稍微比较多的样例程序就会崩···,数量比较少的样例倒是没问题,自己写出来了
4、模拟退火算法,遗传算法,蚁群算法,看了半天的算法介绍,表示自己学不会怎么破···
5、其他算法:禁忌搜索?(其实这个觉得能写,但算法有点不理解····

想问问大神们,有什么好的方法可以过了那17个样例。真心感谢啊······


希望能用C/C++语言实现,不是也没关系。
...全文
4822 10 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
  • 打赏
  • 举报
回复
百度:TSP问题算法小软件 4.0
或者:http://www.onlinedown.net/soft/578727.htm
冷夜1987 2018-01-15
  • 打赏
  • 举报
回复
最加回复,最后少了一个}结尾
冷夜1987 2018-01-15
  • 打赏
  • 举报
回复
import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.List; public class TabuSearchAlgorithm { /** 迭代次数 */ private int MAX_GEN; /** 每次搜索邻居个数 */ private int neighbourhoodNum; /** 禁忌长度 */ private int tabuTableLength; /** 节点数量,编码长度 */ private int nodeNum; /** 节点间距离矩阵 */ private int[][] nodeDistance; /** 当前路线 */ private int[] route; /** 最好的路径 */ public int[] bestRoute; /** 最佳路径总长度 */ private int bestEvaluation; /** 禁忌表 */ private int[][] tabuTable; /** 禁忌表中的评估值 */ private int[] tabuTableEvaluate; private long tp; public TabuSearchAlgorithm() { } /** * constructor of GA * * @param n * 城市数量 * @param g * 运行代数 * @param c * 每次搜索邻居个数 * @param m * 禁忌长度 * **/ public TabuSearchAlgorithm(int n, int g, int c, int m) { nodeNum = n; MAX_GEN = g; neighbourhoodNum = c; tabuTableLength = m; } /** * 初始化Tabu算法类 * * @param filename * 数据文件名,该文件存储所有城市节点坐标数据 * @throws IOException */ public void init(List<String> list) throws IOException { // 读取数据 int[] x; int[] y; String strbuff; nodeDistance = new int[nodeNum][nodeNum]; x = new int[nodeNum]; y = new int[nodeNum]; String[] strcol; for (int i = 0; i < nodeNum; i++) { // 读取一行数据,数据格式1 6734 1453 strbuff = list.get(i); // 字符分割 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 < nodeNum - 1; i++) { nodeDistance[i][i] = 0; // 对角线为0 for (int j = i + 1; j < nodeNum; 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) { nodeDistance[i][j] = tij + 1; nodeDistance[j][i] = nodeDistance[i][j]; } else { nodeDistance[i][j] = tij; nodeDistance[j][i] = nodeDistance[i][j]; } } } nodeDistance[nodeNum - 1][nodeNum - 1] = 0; route = new int[nodeNum]; bestRoute = new int[nodeNum]; bestEvaluation = Integer.MAX_VALUE; tabuTable = new int[tabuTableLength][nodeNum]; tabuTableEvaluate = new int[tabuTableLength]; for (int i = 0; i < tabuTableEvaluate.length; i++) { tabuTableEvaluate[i] = Integer.MAX_VALUE; } } /** 生成初始群体 */ void generateInitGroup() { System.out.println("1.生成初始群体"); boolean iscontinue = false; for (int i = 0; i < route.length; i++) { do { iscontinue = false; route[i] = (int) (Math.random() * nodeNum); for (int j = i - 1; j >= 0; j--) { if (route[i] == route[j]) { iscontinue = true; break; } } } while (iscontinue); // System.out.println("i="+i+", route[i]="+route[i]); } } /** 复制编码体,复制Gha到Ghb */ public void copyGh(int[] Gha, int[] Ghb) { for (int i = 0; i < nodeNum; i++) { Ghb[i] = Gha[i]; } } /** 计算路线的总距离 */ public int evaluate(int[] chr) { // 0123 int len = 0; // 编码,起始城市,城市1,城市2...城市n for (int i = 1; i < nodeNum; i++) { len += nodeDistance[chr[i - 1]][chr[i]]; } // 城市n,起始城市 len += nodeDistance[chr[nodeNum - 1]][chr[0]]; return len; } /** * 随机获取邻域路径 * * @param route * 当前路径 */ public int[] getNeighbourhood(int[] route) { int temp; int ran1, ran2; int[] tempRoute = new int[route.length]; copyGh(route, tempRoute); ran1 = (int) (Math.random() * nodeNum); do { ran2 = (int) (Math.random() * nodeNum); } while (ran1 == ran2); temp = tempRoute[ran1]; tempRoute[ran1] = tempRoute[ran2]; tempRoute[ran2] = temp; return tempRoute; } /** * 随机获取一定数量的领域路径 */ public int[][] getNeighbourhood(int[] route, int tempNeighbourhoodNum) { int[][] NeighbourhoodRoutes = new int[tempNeighbourhoodNum][nodeNum]; List<int[]> tempExchangeNodeList = new ArrayList<>(); int temp; int ran0, ran1; int[] tempRoute = null; boolean iscontinue; for (int i = 0; i < tempNeighbourhoodNum; i++) { tempRoute = new int[route.length]; copyGh(route, tempRoute); do { iscontinue = false; // 随机生成一个邻域; ran0 = (int) (Math.random() * nodeNum); do { ran1 = (int) (Math.random() * nodeNum); } while (ran0 == ran1); // 判断是否重复 for (int j = 0; j < tempExchangeNodeList.size(); j++) { if (tempExchangeNodeList.get(j)[0] < tempExchangeNodeList.get(j)[1]) { if ((ran0 < ran1 && (tempExchangeNodeList.get(j)[0] == ran0 && tempExchangeNodeList.get(j)[1] == ran1)) || (ran0 > ran1 && (tempExchangeNodeList.get(j)[0] == ran1 && tempExchangeNodeList.get(j)[1] == ran0))) { iscontinue = true; } } else { if ((ran0 < ran1 && (tempExchangeNodeList.get(j)[0] == ran1 && tempExchangeNodeList.get(j)[1] == ran0)) || (ran0 > ran1 && (tempExchangeNodeList.get(j)[0] == ran0 && tempExchangeNodeList.get(j)[1] == ran1))) { iscontinue = true; } } } if (iscontinue == false) { temp = tempRoute[ran0]; tempRoute[ran0] = tempRoute[ran1]; tempRoute[ran1] = temp; // 判断是否与route相同 for (int j = 0; j < tempRoute.length; j++) { if (tempRoute[j] != route[j]) { iscontinue = false; } } if (iscontinue == false && !isInTabuTable(tempRoute)) { NeighbourhoodRoutes[i] = tempRoute; } else { iscontinue = true; } } } while (iscontinue); } return NeighbourhoodRoutes; } /** 判断路径是否在禁忌表中 */ public boolean isInTabuTable(int[] tempRoute) { int i, j; int flag = 0; for (i = 0; i < tabuTableLength; i++) { flag = 0; for (j = 0; j < nodeNum; j++) { if (tempRoute[j] != tabuTable[i][j]) { flag = 1;// 不相同 break; } } if (flag == 0) {// 相同,返回存在相同 break; } } if (i == tabuTableLength) {// 不等 return false;// 不存在 } else { return true;// 存在 } } /** 解禁忌与加入禁忌,注意禁忌策略的选择 */ public void flushTabuTable(int[] tempGh) { int tempValue = evaluate(tempGh); // 找到禁忌表中路径的最大值; int tempMax = tabuTableEvaluate[0]; int maxValueIndex = 0; for (int i = 0; i < tabuTableLength; i++) { if (tabuTableEvaluate[i] > tempMax) { tempMax = tabuTableEvaluate[i]; maxValueIndex = i; } } // 新的路径加入禁忌表 if (tempValue < tabuTableEvaluate[maxValueIndex]) { if (tabuTableEvaluate[maxValueIndex] < Integer.MAX_VALUE) { copyGh(tabuTable[maxValueIndex], route); } System.out.println("测试点:更新禁忌表,maxValueIndex= " + maxValueIndex); for (int k = 0; k < nodeNum; k++) { tabuTable[maxValueIndex][k] = tempGh[k]; } tabuTableEvaluate[maxValueIndex] = tempValue; } } /** 启动禁忌搜索 */ public void startSearch() { int nn; int neighbourhoodEvaluation; int currentBestRouteEvaluation; /** 存放邻域路径 */ int[] neighbourhoodOfRoute = new int[nodeNum]; /** 当代最好路径 */ int[] currentBestRoute = new int[nodeNum]; /** 当前代数 */ int currentIterateNum = 0; /** 最佳出现代数 */ int bestIterateNum = 0; int[][] neighbourhoodOfRoutes = null; // 用于控制迭代次数 int[] priviousRoute = new int[nodeNum]; // 初始化编码Ghh generateInitGroup(); // 将当前路径作为最好路径 copyGh(route, bestRoute); currentBestRouteEvaluation = evaluate(route); bestEvaluation = currentBestRouteEvaluation; System.out.println("2.迭代搜索...."); while (currentIterateNum < MAX_GEN) { for (int i = 0; i < route.length; i++) { priviousRoute[i] = route[i]; } neighbourhoodOfRoutes = getNeighbourhood(route, neighbourhoodNum); System.out.println("测试点:currentIterateNum= " + currentIterateNum); for (nn = 0; nn < neighbourhoodNum; nn++) { // 得到当前路径route的一个邻域路径neighbourhoodOfRoute // neighbourhoodOfRoute=getNeighbourhood(route); neighbourhoodOfRoute = neighbourhoodOfRoutes[nn]; neighbourhoodEvaluation = evaluate(neighbourhoodOfRoute); // System.out.println("测试:neighbourhoodOfRoute="+neighbourhoodEvaluation); if (neighbourhoodEvaluation < currentBestRouteEvaluation) { copyGh(neighbourhoodOfRoute, currentBestRoute); currentBestRouteEvaluation = neighbourhoodEvaluation; // System.out.println("测试:neighbourhoodOfRoute="+neighbourhoodEvaluation); } } if (currentBestRouteEvaluation < bestEvaluation) { bestIterateNum = currentIterateNum; copyGh(currentBestRoute, bestRoute); bestEvaluation = currentBestRouteEvaluation; System.out.println("测试:currentBestRouteEvaluation=" + currentBestRouteEvaluation); } copyGh(currentBestRoute, route); // 解禁忌表,currentBestRoute加入禁忌表 // System.out.println("测试点:currentBestRoute= "+currentBestRoute); flushTabuTable(currentBestRoute); currentIterateNum++; for (int i = 0; i < priviousRoute.length; i++) { if (priviousRoute[i] != route[i]) { currentIterateNum = 0; break; } } printRunStatus(); } // 结果显示: System.out.println("最佳长度出现代数:"); System.out.println(bestIterateNum); System.out.println("最佳长度:"); System.out.println(bestEvaluation); System.out.println("最佳路径:"); for (int i = 0; i < nodeNum; i++) { System.out.print(bestRoute[i] + ","); } } /** * @Description: 输出结运行状态 */ private void printRunStatus() { System.out.println("最优路径长度:" + bestEvaluation); } public static void main(String[] args) throws IOException { System.out.println("Start...."); List<String> listSearch = new ArrayList<String>(); listSearch.add("1,10017,3884"); listSearch.add("2,10016,3883"); listSearch.add("3,10007,3887"); TabuSearchAlgorithm tabu = new TabuSearchAlgorithm(listSearch.size(), 120, 500, 5); tabu.init(listSearch); tabu.startSearch(); } 这个是禁忌算法的代码,参数第一个是编号,第二个是坐标点距离子午0度线的x坐标,第三是坐标的距离赤道的y坐标
qq_29066673 2017-09-20
  • 打赏
  • 举报
回复
楼主大大,可以分享一下禁忌搜索算法求本题的方法吗
flysnowtiger 2016-09-27
  • 打赏
  • 举报
回复
楼主好,能给我把禁忌搜索的代码发我么?跪求,楼主好人【可怜样】
mxway 2015-06-05
  • 打赏
  • 举报
回复
找个蚁群算法的源码,一行行的看,蚁群算法求tsp源码也就200行以内。最复杂也就是双重循环。用心看应该没问题。
赫爾修羅-韋 2015-06-05
  • 打赏
  • 举报
回复
谢谢了,我写好了另一种叫作,禁忌搜索的算法,弄好了。thx
赫爾修羅-韋 2015-06-04
  • 打赏
  • 举报
回复
然而我这种学渣表示学不会这么高级的算法TAT
mxway 2015-06-04
  • 打赏
  • 举报
回复
模拟退火算法,遗传算法,蚁群算法这几个算法求出来的不是最优解。而是相对较优解。不论最大城市是52还是58,0,1,2,3想要求出最优解都不特现实。对于城市数较大的tsp,基本上就是使用模拟退火算法,遗传算法,蚁群算法求出相对较优解。

65,186

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧