分支定界法求解旅行商问题
0、问题梗概
旅行商问题(TravelingSalesmanProblem,TSP)是一个经典的组合优化问题。经典的TSP可以描述为:一个商品推销员要去若干个城市推销商品,该推销员从一个城市出发,需要经过所有城市后,回到出发地。应如何选择行进路线,以使总的行程最短。
1、随机数据的初始概率密度函数
2、程序运行数据
运行次数 | 时间(维数23) | 时间(维数33) |
---|---|---|
1 | 3.06541 ms | 26.9593 ms |
2 | 3.65156 ms | 48.6972 ms |
3 | 2.66832 ms | 43.5297 ms |
4 | 6.78412 ms | 44.7827 ms |
5 | 9.77699 ms | 24.6574 ms |
6 | 4.44002 ms | 24.3777 ms |
7 | 9.36337 ms | 20.4059 ms |
8 | 7.22274 ms | 45.9999 ms |
9 | 8.77502 ms | 41.7881 ms |
10 | 8.07504 ms | 66.3793 ms |
维度 23 的平均执行时间为 6.4 毫秒,维度 33 的平均执行时间为 38.8 毫秒。
3、代码分析
I)使用数据类型
using mat_d = vector<vector<double>>;
using path_t = vector<pair<size_t, size_t>>;
II) 随机数据的初始概率密度函数
double F(double x)
{return (5 / 6.0) * (1 + pow(x, 4));
}
// use Acceptance-Rejection Method
// max from 0 to 1 in function F is 5/3
double GetRnd()
{double u1, u2;while (true){u1 = rand() % MAX_DIST;u2 = rand() % MAX_DIST;if (u2 <= (3 / 5.0) * F(u1))return u1;}
}
III) 任务路径树
// Task tree node represents each reduction matrix
class TaskTree
{private:double bound;int index_row, index_col;
public:mat_d mat;path_t path;TaskTree(const mat_d &m, const path_t &p = {}, const double b = 0);void PrintMat();void ReduceMinElem();void FindMinPath();bool PathCompleted() { return path.size() == mat.size(); }double GetBound() { return bound; }int GetRowIndex() { return index_row; }int GetColIndex() { return index_col; }
};
IV) 选取路径中最小元素后进行规约操作
// Minimum statute
void TaskTree::ReduceMinElem()
{for (size_t i = 0; i < mat.size(); i++){double minelem_row = INF;for (size_t j = 0; j < mat.size(); j++){if (minelem_row > mat[i][j]){minelem_row = mat[i][j];}}for (size_t j = 0; j < mat.size(); j++){if (mat[i][j] != INF){mat[i][j] -= minelem_row;}}if (minelem_row != INF)bound += minelem_row;}for (size_t i = 0; i < mat.size(); i++){double minelem_col = INF;for (size_t j = 0; j < mat.size(); j++){if (minelem_col > mat[j][i]){minelem_col = mat[j][i];}}for (size_t j = 0; j < mat.size(); j++){if (mat[j][i] != INF){mat[j][i] -= minelem_col;}}if (minelem_col != INF)bound += minelem_col;}FindMinPath();
}
V) 寻找最小元素过程
// Find the shortest path possible
void TaskTree::FindMinPath()
{index_row = -1;index_col = -1;double max_sum = -1;for (size_t i = 0; i < mat.size(); i++){for (size_t j = 0; j < mat.size(); j++){if (mat[i][j] == 0){double min_row = INF, min_col = INF;for (size_t k = 0; k < mat.size(); k++){if (k != j && mat[i][k] < min_row)min_row = mat[i][k];if (k != i && mat[k][j] < min_col)min_col = mat[k][j];}double max_sum_tmp = min_row + min_col;if (max_sum_tmp > max_sum){index_row = i;index_col = j;max_sum = max_sum_tmp;}}}}path.push_back(make_pair(index_row, index_col));
}
VI) 左子树情况为选取最小元素加入路径,右子树情况为不选取该元素
// Subtree containing the selected path
shared_ptr<TaskTree> SetLeft(const mat_d &m, const path_t &path, const double bound, const int index_row, const int index_col)
{mat_d mat = m;map<size_t, size_t> pathTest;for (size_t i = 0; i < path.size() - 1; i++){pathTest[path[i].first] = path[i].second;}size_t pos = index_col;while (pathTest.find(pos) != pathTest.end()){pos = pathTest[pos];if (pos == index_row){return nullptr;}}for (size_t i = 0; i < mat.size(); i++){mat[index_row][i] = INF;mat[i][index_col] = INF;}mat[index_col][index_row] = INF;
return make_shared<TaskTree>(mat, path, bound);
}
// Does not contain the subtree of the selected path
shared_ptr<TaskTree> SetRight(const mat_d &m, const path_t &p, const double bound, const int index_row, const int index_col)
{mat_d mat = m;mat[index_row][index_col] = INF;
path_t path = p;path.pop_back();return make_shared<TaskTree>(mat, path, bound);
}
VII) 对旅行商问题解决进行二次封装
// Problem-solving tree
class Task
{private:map<size_t, size_t> bestpath;list<shared_ptr<TaskTree>> tour;mat_d origin_mat;double best;shared_ptr<TaskTree> root;
public:Task(const size_t size, double (*pf)() = GetRnd);Task(const char *filename, const size_t size);void RunTask();void PrintPath();
};
VIII) 解决问题过程,核心思路优先考虑左子树以加快收敛过程
void Task::RunTask()
{tour.push_front(root);// root->PrintMat();while (tour.size() != 0){shared_ptr<TaskTree> head = tour.front();tour.pop_front();if (head->GetBound() > best){continue;}if (head->PathCompleted()){best = head->GetBound();bestpath.clear();for (size_t i = 0; i < origin_mat.size(); i++){bestpath[head->path[i].first] = head->path[i].second;}continue;}if (head->GetRowIndex() == -1 && head->GetColIndex() == -1){continue;}shared_ptr<TaskTree> left = SetLeft(head->mat, head->path, head->GetBound(), head->GetRowIndex(), head->GetColIndex());shared_ptr<TaskTree> right = SetRight(head->mat, head->path, head->GetBound(), head->GetRowIndex(), head->GetColIndex());if (left != nullptr){if (left->path.size() < origin_mat.size()){if (left->GetBound() < right->GetBound()){tour.push_front(right);tour.push_front(left);}else{tour.push_front(left);tour.push_front(right);}
#if 0
cout << "bound: " << tour.front()->GetBound() << endl;
head->PrintMat();
#endif}else{tour.push_front(left);}}else{tour.push_front(right);}}PrintPath();
}
IX) 打印总体路径
void Task::PrintPath()
{cout << "Best path: 1 => ";size_t begin = 0;while (bestpath[begin] != 0){cout << bestpath[begin] + 1 << " => ";begin = bestpath[begin];}cout << "1" << endl;cout << "best tour: " << best << endl;
}
X) 主函数
int main()
{const auto start_time = high_resolution_clock::now();srand(time(NULL));const size_t nDim1 = 6, nDim2 = 33;
#if 0
Task t1("input.txt", nDim1);
t1.RunTask();
#endif
#if 1Task t2(nDim2);t2.RunTask();
#endifconst auto end_time = high_resolution_clock::now();PrintTime(start_time, end_time);
}
4、代码总评
Best path: 1 => 29 => 12 => 32 => 23 => 11 => 15 => 24 => 14 => 5 => 8 => 17 => 25 => 26 => 33 => 20 => 18 => 9 => 13 => 16 => 31 => 30 => 3 => 21 => 2 => 19 => 10 => 28 => 27 => 22 => 4 => 7 => 6 => 1
best tour: 239
Time: 19.0621 ms
智能指针设计在一定程度上简化了内存管理,避免了内存泄漏的问题。 一个显着的优点是尽可能多地使用指针,而不是重新创建对象,这样整个程序占用的内存很少。 从算法设计的角度来看,优先考虑左子树(即路径),这使得代码更加高效。
完整代码: https://github.com/KCNyu/Program_MSU-BIT/blob/master/C%2B%2B_LECTURE/TSP/TSP.cpp
分支定界法求解旅行商问题相关推荐
- MATLAB实战系列(二十九)-头脑风暴优化(BSO)算法求解旅行商问题(TSP)-交叉算子
前言 代码明细可参见 MATLAB实战系列(八)-头脑风暴优化(BSO)算法求解旅行商问题(TSP)(附MATLAB代码) 交叉算子的实现机制 我们还是以求解TSP问题为例,8个城市的坐标如下所示. ...
- 模拟退火算法求解旅行商问题(python实现)
模拟退火算法求解旅行商问题 文章目录 模拟退火算法求解旅行商问题 一.模拟退火算法原理 二.旅行商问题 1.求解思路 2.代码 总结 旅行商问题(TSP 问题).假设有一个旅行商人要拜访全国31个省会 ...
- 计算机设计大赛国奖作品_5. 模拟退火求解旅行商问题
计算机设计大赛国奖作品_5. 模拟退火求解旅行商问题 本系列是2021年中国大学生计算机设计大赛作品"环境监测无人机航线优化"的相关文档,获得2021年西北赛区一等奖,国赛三等奖. ...
- 【MVO TSP】基于matlab灰狼算法求解旅行商问题【含Matlab源码 1327期】
一.获取代码方式 获取代码方式1: 完整代码已上传我的资源:[TSP]基于matlab灰狼算法求解旅行商问题[含Matlab源码 1327期] 点击上面蓝色字体,直接付费下载,即可. 获取代码方式2: ...
- MATLAB实现分支定界法求解整数规划
利用MATLAB实现分支定界法求解整数规划 classdef Model < matlab.mixin.CopyablepropertiesintconlbubsolverAineqbineqA ...
- 【GA TSP】基于matlab遗传算法求解旅行商问题【含Matlab源码 1337期】
一.获取代码方式 获取代码方式1: 完整代码已上传我的资源:[TSP]基于matlab遗传算法求解旅行商问题[含Matlab源码 1337期] 点击上面蓝色字体,直接付费下载,即可. 获取代码方式2: ...
- 【路径规划-TSP问题】基于粒子群结合蚁群算法求解旅行商问题附matlab代码
1 内容介绍 一种基于粒子群优化的蚁群算法求解TSP问题的方法.该方法在求解TSP问题时,利用粒子群优化的思想,对蚁群算法的参数取值进行优化并选择.在粒子群算法中,将蚁群算法的5个参数(q,α,β,ρ ...
- pso解决tsp matlab,计算智能课程设计_粒子群优化算法求解旅行商问题_Matlab实现.doc...
计算智能课程设计_粒子群优化算法求解旅行商问题_Matlab实现.doc 摘要:TSP是一个典型的NPC问题.本文首先介绍旅行商问题和粒子群优化算法的基本概念.然后构造一种基于交换子和交换序[1]概念 ...
- 【PSO TSP】基于matlab GUI粒子群算法求解旅行商问题【含Matlab源码 1334期】
⛄一.TSP简介 旅行商问题,即TSP问题(Traveling Salesman Problem)又译为旅行推销员问题.货郎担问题,是数学领域中著名问题之一.假设有一个旅行商人要拜访n个城市,他必须选 ...
- 单目标应用:瞪羚优化算法GOA求解旅行商问题TSP(提供Matlab代码)
一.瞪羚优化算法 瞪羚优化算法(Gazelle Optimization Algorithm,GOA)由Agushaka等人于2022年提出,该算法模拟了瞪羚逃避捕食者的行为,思路新颖,性能高效. 瞪 ...
最新文章
- 计算机应用基础第三章操作步骤,最新江西三校生计算机应用基础模拟操作题集锦(超实用!)...
- Oracle数据库的数据统计(Analyze)
- 【Network】高性能 UDP 服务应该怎么搞?
- BZOJ4591 SHOI2015超能粒子炮·改(卢卡斯定理+数位dp)
- 【高并发】怎么演示公平锁和非公平锁?
- seaborn_Seaborn Kdeplot –综合指南
- eclipse adt bundle不显示Android SDK菜单
- PHP 互联网架构师成长之路*「swoole」终极指南
- oppo小布机器人_OPPO小布助手2.0强势来袭 三大版块迎来重大升级
- python负数的处理
- 概率统计Python计算:全概率公式
- 抖音同款 抖音 城堡 微信背景图,抖音城堡微信背景图
- SDUT ACM 多项式求和(基于C语言)
- 【Fracturing amp; Destruction】Unity3D的物体爆裂、炸裂、碎裂效果
- accept()函数
- python中的对象是什么意思_python中什么是对象
- 【创建Vue手脚架项目】
- mysql为什么会慢
- c语言的four是什么意思,【转】一些变态的编程语言
- 「工具」三分钟了解一款在线流程绘制工具:Whimsical
热门文章
- jQuery实现下拉菜单[代码+详细讲解+效果图]
- VBScript 教程
- ecshop二次开发之模板整合
- 从四大造字法看文字所承载的文化_汉语汉字所承载的文化信息最好能举例说明...
- 仿vista桌面小工具
- kali linux启动盘工具,白话kali linux USB启动盘的制作(快捷版)
- java 主板序列号_Java获得硬盘和主板的序列号
- mysql-front源码_MySQL-Front
- 服务器搬迁方案_服务器数据迁移方案
- 2109-全国大学生电子设计竞赛-F-纸张数识别(内含arduino代码以及题解)