【opencv】示例-travelsalesman.cpp 使用模拟退火算法求解旅行商问题

news2024/10/6 18:27:20

0446b2afe218c87af03978969e6983bd.png

6eb23516b6dbfac595d1d35f62b8b3ee.png

3f6ce269db2eaaf6bfd4d672d76e98e1.png

// 载入 OpenCV 的核心头文件
#include <opencv2/core.hpp>
// 载入 OpenCV 的图像处理头文件
#include <opencv2/imgproc.hpp>
// 载入 OpenCV 的高层GUI(图形用户界面)头文件
#include <opencv2/highgui.hpp>
// 载入 OpenCV 的机器学习模块头文件
#include <opencv2/ml.hpp>


// 使用命名空间cv,避免每次调用 OpenCV 的功能时都要前缀cv::
using namespace cv;


// 定义旅行商(TravelSalesman)类
class TravelSalesman
{
private :
    // 私有成员:城市位置向量的引用
    const std::vector<Point>& posCity;
    // 私有成员:下一个城市索引的向量引用
    std::vector<int>& next;
    // 私有成员:随机数生成器
    RNG rng;
    // 私有成员:用于记录状态改变的城市索引
    int d0,d1,d2,d3;


public:
    // 构造函数初始化城市位置和下一个城市的索引
    TravelSalesman(std::vector<Point> &p, std::vector<int> &n) :
        posCity(p), next(n)
    {
        // 初始化随机数生成器
        rng = theRNG();
    }
    // 返回系统状态的能量值
    double energy() const;
    // 改变系统状态(随机扰动)
    void changeState();
    // 撤销到之前的状态
    void reverseState();


};


// 实现改变状态的函数
void TravelSalesman::changeState()
{
    // 产生随机城市索引
    d0 = rng.uniform(0,static_cast<int>(posCity.size()));
    // 获取随机城市后的各个城市索引
    d1 = next[d0];
    d2 = next[d1];
    d3 = next[d2];


    // 更改城市访问的顺序
    next[d0] = d2;
    next[d2] = d1;
    next[d1] = d3;
}


// 实现撤销状态改变的函数
void TravelSalesman::reverseState()
{
    // 恢复原来的城市访问顺序
    next[d0] = d1;
    next[d1] = d2;
    next[d2] = d3;
}


// 实现计算能量值的函数,能量值为城市间距离的总和
double TravelSalesman::energy() const
{
    // 初始化能量值
    double e = 0;
    // 遍历城市计算总距离
    for (size_t i = 0; i < next.size(); i++)
    {
        // 计算两城市间距离并累加到能量值
        e += norm(posCity[i]-posCity[next[i]]);
    }
    // 返回总能量值
    return e;
}


// 绘制每个城市点和城市间连线
static void DrawTravelMap(Mat &img, std::vector<Point> &p, std::vector<int> &n)
{
    // 遍历所有城市
    for (size_t i = 0; i < n.size(); i++)
    {
        // 在图像中用小圆点表示城市位置
        circle(img,p[i],5,Scalar(0,0,255),2);
        // 连接城市间的线表示旅行路径
        line(img,p[i],p[n[i]],Scalar(0,255,0),2);
    }
}


int main(void)
{
    // 设置城市数量
    int nbCity=40;
    // 创建图像,用于显示城市地图
    Mat img(500,500,CV_8UC3,Scalar::all(0));
    // 初始化随机数生成器,种子为123456
    RNG rng(123456);
    // 设置城市生成的半径范围
    int radius=static_cast<int>(img.cols*0.45);
    // 设置图像中心点位置
    Point center(img.cols/2,img.rows/2);


    // 初始化城市位置向量和下一个城市索引向量
    std::vector<Point> posCity(nbCity);
    std::vector<int> next(nbCity);
    // 随机生成城市位置
    for (size_t i = 0; i < posCity.size(); i++)
    {
        // 在圆周上均匀分布城市
        double theta = rng.uniform(0., 2 * CV_PI);
        // 计算城市的坐标并存储
        posCity[i].x = static_cast<int>(radius*cos(theta)) + center.x;
        posCity[i].y = static_cast<int>(radius*sin(theta)) + center.y;
        // 设定下一个城市的索引
        next[i]=(i+1)%nbCity;
    }
    // 创建旅行商问题系统实例
    TravelSalesman ts_system(posCity, next);


    // 绘制初始的旅行商问题地图
    DrawTravelMap(img,posCity,next);
    // 显示地图窗口
    imshow("Map",img);
    // 短暂等待时间
    waitKey(10);
    // 初始化模拟退火算法的当前温度
    double currentTemperature = 100.0;
    // 模拟退火循环,直到连续10次没有改变发生时停止
    for (int i = 0, zeroChanges = 0; zeroChanges < 10; i++)
    {
        // 执行模拟退火算法,尝试改变系统状态
        int changesApplied = ml::simulatedAnnealingSolver(ts_system, currentTemperature, currentTemperature*0.97, 0.99, 10000*nbCity, &currentTemperature, rng);
        // 重绘图像,显示新的旅行路径
        img.setTo(Scalar::all(0));
        DrawTravelMap(img, posCity, next);
        imshow("Map", img);
        // 短暂等待时间并检查是否有退出键被按下
        int k = waitKey(10);
        // 输出当前循环的信息
        std::cout << "i=" << i << " changesApplied=" << changesApplied << " temp=" << currentTemperature << " result=" << ts_system.energy() << std::endl;
        // 如果用户按下退出键,则退出程序
        if (k == 27 || k == 'q' || k == 'Q')
            return 0;
        // 如果没有改变发生,则计数器加1
        if (changesApplied == 0)
            zeroChanges++;
    }
    // 完成模拟退火算法,输出结束信息
    std::cout << "Done" << std::endl;
    // 等待用户按键以退出
    waitKey(0);
    // 程序结束
    return 0;
}

这段代码实现了一个使用模拟退火算法的旅行商问题解决方案。在这个解决方案中,首先随机在一个圆周上生成一定数量的城市,并在地图上用圆点和连线显示出旅行商访问城市的路径。然后,通过模拟退火算法不断尝试随机扰动城市访问的顺序,通过最小化城市间路径的总长度来寻找最优解(即最短路径)。代码中绘图部分使用了OpenCV库,而模拟退火的具体实现使用了OpenCV的机器学习模块。

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

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

相关文章

Devin AI: The World’s First AI Software Engineer

Devin AI是Cognition AI团队推出的一款名为Devin的人工智能软件工程师&#xff0c;它被誉为世界上第一个完全自主的AI软件工程师。Devin AI在2024年3月12日发布&#xff0c;并在SWE-bench编码基准测试中设立了新的技术标杆。 Devin AI具备多项强大的能力&#xff0c;包括学习如…

简述OSI七层模型及每层的功能任务和协议

文章目录 一、OSI七层模型的功能和任务1.物理层2.数据链路层3.网络层4.传输层5.会话层6.表示层7. 应用层 二、OSI七层模型每层的协议 开放系统互连参考模型&#xff08;Open System Interconnect&#xff0c;简称OSI&#xff09;是国际标准化组织(ISO)和国际电报电话咨询委员会…

openstack安装dashboard后登录网页显示404错误

1. 2.进入该目录vim /etc/httpd/conf.d/openstack-dashboard.conf 增加这一行 WSGIApplicationGroup %{GLOBAL} 重启httpd后就可以访问了

SpringBoot+FreeMaker

目录 1.FreeMarker说明2.SpringBootFreeMarker快速搭建Pom文件application.properties文件Controller文件目录结构 3.FreeMarker数据类型3.1.布尔类型3.2.数值类型3.3.字符串类型3.4.日期类型3.5.空值类型3.6.sequence类型3.7.hash类型 4.FreeMarker指令assign自定义变量指令if…

[大模型]DeepSeek-7B-chat FastApi 部署调用

DeepSeek-7B-chat FastApi 部署调用 DeepSpeek 介绍 由70亿个参数组成的高级语言模型 DeepSeek LLM。它是在一个包含2万亿个英文和中文代币的庞大数据集上从零开始训练的。为了促进研究&#xff0c;DeepSeek 已经为研究社区开放了DeepSeek LLM 7B/67B Base 和 DeepSeek LLM 7…

软考129-上午题-【软件工程】-McCabe度量法+白盒测试真题

一、真题 真题1&#xff1a; 简单路径&#xff1a; 简单路径是指在一个图中&#xff0c;从一个顶点出发&#xff0c;经过一系列不同的顶点&#xff0c;最终到达另一个顶点&#xff0c;且在整个过程中&#xff0c;除了起点和终点外&#xff0c;每个顶点只被访问一次的路径。在简…

Linux 目录结构与基础查看命令

介绍 目录结构如下 /bin&#xff1a;存放着用户最经常使用的二进制可执行命令&#xff0c;如cp、ls、cat等。这些命令是系统管理员和普通用户进行日常操作所必需的。 /boot&#xff1a;存放启动系统使用的一些核心文件&#xff0c;如引导加载器&#xff08;bootstrap loader…

商业银行业务与管理

商业银行业务与管理 资产负债表恒等式中国商业银行的资产负债表商业银行的业务种类银行运行管理的案例银行管理的基本准则流动性管理资产和负债管理资本充足管理 资产负债表恒等式 &#xff08;一般&#xff09;资产负债所有者权益 一个公司的资产是由负债和所有者权益所构成…

飞驰云联入选金融信创生态实验室「金融信创优秀解决方案」

近日&#xff0c;由中国人民银行领导、中国金融电子化集团有限公司牵头组建的金融信创生态实验室发布了第三期金融信创优秀解决方案&#xff0c;Ftrans飞驰云联“文件数据传输解决方案”成功入选&#xff01; 本次金融信创优秀解决方案遴选经方案征集、方案初审、专家评审等多环…

【MATLAB源码-第188期】基于matlab的64QAM系统相位偏移估计EOS算法仿真,对比补偿前后的星座图误码率。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 1. 引言 M-QAM调制技术的重要性 现代通信系统追求的是更高的数据传输速率和更有效的频谱利用率。M-QAM调制技术&#xff0c;作为一种高效的调制方案&#xff0c;能够通过在相同的带宽条件下传输更多的数据位来满足这一需求…

《自动机理论、语言和计算导论》阅读笔记:p172-p224

《自动机理论、语言和计算导论》学习第 8 天&#xff0c;p172-p224总结&#xff0c;总计 53 页。 一、技术总结 1.Context-Free Grammar(CFG) 2.parse tree (1)定义 p183&#xff0c;But perhaps more importantly, the tree, known as a “parse tree”, when used in a …

【Java】新手一步一步安装 Java 语言开发环境

文章目录 一、Windows 10 系统 安装 JDK8二、 Mac 系统 安装 JDK8三、IDEA安装 一、Windows 10 系统 安装 JDK8 &#xff08;1&#xff09;打开 JDK下载网站&#xff0c;根据系统配置选择版本&#xff0c;这里选择windows 64位的版本&#xff0c;点击下载&#xff08;这里需要…

考试酷基本功修炼课学习历程_FPGA成长篇

本文为明德扬原创文章&#xff0c;转载请注明出处&#xff01;作者&#xff1a;明德扬学员&#xff1a;考试酷账号&#xff1a;11167760 我是硬件工程师&#xff0c;日常工作中主要跟数字电路、模拟电路、嵌入式系统打交道&#xff0c;当然也会涉及到FPGA&#xff0c;但是苦于…

学习笔记之——3DGS-SLAM系列代码解读

最近对一系列基于3D Gaussian Splatting&#xff08;3DGS&#xff09;SLAM的工作的源码进行了测试与解读。为此写下本博客mark一下所有的源码解读以及对应的代码配置与测试记录~ 其中工作1~5的原理解读见博客&#xff1a; 学习笔记之——3D Gaussian Splatting及其在SLAM与自动…

mac电脑软件 Magnet v2.14.0免激活中文版

Magnet是一款窗口管理工具&#xff0c;适用于Mac操作系统。它可以帮助用户轻松地管理和组织多个应用程序的窗口&#xff0c;提高工作效率。 Magnet支持多种窗口布局和组合方式&#xff0c;可以将窗口分为左右、上下、四分之一等不同的比例和位置&#xff0c;用户可以根据实际需…

Vue入门:天不生Vue,前端万古如长夜 - Vue从入门到放弃

&#x1f44b; Vue环境搭建 首先&#xff0c;搭一个打代码的环境 1.安装node.js 在使用VS Code之前&#xff0c;需要安装Vue的开发环境。 安装Vue的最简单方法是使用npm包管理器&#xff0c;先安装Node.js和npm。 node官网 ​​ 2.配置环境变量 在nodejs安装目录下新建…

强大的压缩和解压缩工具 Keka for Mac

Keka for Mac是一款功能强大的压缩和解压缩工具&#xff0c;专为Mac用户设计。它支持多种压缩格式&#xff0c;包括7z、Zip、Tar、Gzip和Bzip2等&#xff0c;无论是发送电子邮件、备份文件还是节省磁盘空间&#xff0c;Keka都能轻松满足用户需求。 这款软件的操作简单直观&…

Android ParcelFileDescriptor实现进程间通信

需求 一个通信通道&#xff0c;实现跨进程的的Socket网络通信。 具体的通信通道的图如下。 需求分析 我们需要一个进程一直做通信通道的事情&#xff0c;业务进程把数据通过进程间通信交给通信进程。通信进程通过Socket通道将数据发给网络另外一端的通信进程。接收端的通信进…

【Web】DASCTF X GFCTF 2022十月挑战赛题解

目录 EasyPOP hade_waibo EasyLove BlogSystem EasyPOP 先读hint.php sorry.__destruct -> secret_code::secret() exp: $anew sorry(); $bnew secret_code(); $a->password"suibian"; $a->name"jay"; echo serialize($a); 真暗号啊&…

【SQL】数据库SQL语句

1、主键 主键值唯一&#xff0c;不可修改&#xff0c;不能为空&#xff0c;删除不能重用 2、数据类型&#xff08;常用&#xff09; char int float date timestamp 3、select select * from data; select xx,xxx from data;//取部分行 select * from data limit 100; //限…