蚁群算法原理及c++实现

article/2025/10/3 5:16:59

参考博客
https://blog.csdn.net/Oudasheng/article/details/84994336
https://blog.csdn.net/wayjj/article/details/72809344#commentsedit
https://blog.csdn.net/Oudasheng/article/details/84994336
https://www.cnblogs.com/mahaitao/p/5572095.html
https://www.cnblogs.com/Horizon-asd/p/12723886.html
https://blog.csdn.net/chen10217/article/details/100762552

一、原理

1. 蚂蚁觅食行为

蚁群在寻找食物时,总能找到一条蚁穴到食物的最短路径,并且能随着环境的变化而更新最优路径。究其原因,是因为蚂蚁在运动过程中,会在所经过路径上留下一种称为信息素(pheromone)的物质,其他蚂蚁在运动中可以感知到这种物质,并以此来指导自己的运动方向。
蚁群的这种行为表现出一种信息正反馈现象:某一路径上走过的蚂蚁越多,则后来者选择该路径的概率越大。

2.蚁群算法

又称蚂蚁算法,是一种基于群体智能的算法,用来在图中寻找优化路径的概率型。它由Marco Dorigo于1992年在他的博士论文中提出,其灵感来源于蚂蚁在寻找食物过程中发现路径的行为。在解决实际问题时,人工蚁群相较于自然蚁群有一定的记忆能力,可记住已访问过的节点,其次人工蚁群在选择路径时依照一定规律,并不是盲目的。蚁群算法常用来解决路径规划等离散优化问题,如旅行商问题(TSP)、指派问题、调度问题。

2,1 特点

  1. 正反馈:可较快发现较优解。
  2. 分布式:基于种群的进化算法,本质具有并行性,易于并行实现。
  3. 启发式搜索:反映搜索中的的先验性和确定性因素(如距离)强度。
  4. 鲁棒性强:不易受某个个体影响。

2.2 算法流程(以TSP问题为例)

TSP问题:一商人去n个城市销货,所有城市走一遍再回到起点,使所走路程最短。

  1. 初始化相关参数:蚁群规模、信息素因子、启发函数因子、信息素挥发因子、信息素常数和最大迭代次数等。将城市信息读入程序并进行预处理,即将城市间信息转化为矩阵。
  2. 随机将蚂蚁放入不同出发点,计算每个蚂蚁的下一步要访问的城市,直到有蚂蚁访问完所有城市。
  3. 计算每个蚂蚁经过的路径长度Lk,记录当前迭代次数下的最优解(访问完所有城市且路径长度最短),更新各条路径上的信息素浓度。
  4. 断是否达到最大迭代次数,若否则返回步骤2,若是则顺序执行。
  5. 输出最优路径和相关指标,如运行时间和迭代次数。

2.3 相关公式

在这里插入图片描述
在这里插入图片描述

2.4 流程图

在这里插入图片描述

三、例子

试设计一个并行算法,求下图中一个源点到其他定点的最短路径。(VS2019+Eigen)
在这里插入图片描述

3.1 关键代码

数据结构:

将蚂蚁设置为一个结构体,包含所在位置、禁忌表、所走路径和是否到达终点标志四项内容。为了便于计算,将信息素、启发信息与距离信息分别在8*8的矩阵中存放,这样可以调用Eigen库直接进行矩阵计算,达到更新信息素的目的。
城市也设为一个结构体,包含城市编号和选择概率两项内容。这里将城市设置为结构体,主要是考虑到在选择下一步行进城市时,要先计算选择概率再通过轮盘赌来确定下一步城市,轮盘赌时需要将城市编号与其选择概率一一对应。
具体代码部分如下:

struct ant                 //蚂蚁结构体
{int loc;               //位置int tabu[cityNum];     //禁忌表int antPath[pathNum];  //走过的路bool flag;             //是否到达终点7
};
struct ant ants[antNum];   //蚁群typedef Matrix<double, 8, 8> Matrix8d;
Matrix8d dist;             //距离矩阵
Matrix8d pher;             //信息素矩阵
Matrix8d nextPher;         //下一代信息素矩阵
Matrix8d insp;             //启发信息矩阵struct city                //城市结构体
{int num;               //编号double prob;           //选择概率
};
struct city cityProb[cityNum];    //可到达城市组
double lineCityProb[cityNum];     //线性化 可到达城市的选择概率

城市选择方式

当蚂蚁k选择下一步要去的城市时,有以下几个步骤:

  1. 对照蚂蚁k的禁忌表,求出下一步所有可去的城市各自的选择概率(概率计算见公式(1));
  2. 线性化所有可去城市的概率,生成介于0~1之间的随机数(线性化概率的目的是实现轮盘赌);
  3. 使用轮盘赌方法选择下一步要去的城市。
    概率计算与轮盘赌选择对应代码片如下:
//轮盘赌选择下一步行进城市
int citySelect(int k, int f)
{int c = 0;//记录蚂蚁可行进的城市个数//1、计算可行进的各城市 选择概率for (int m = 0; m < cityNum; m++){//若城市(i,j)之间有路且j不在蚂蚁k的禁忌表中,则计算概率if (dist(ants[k].loc, m) != -1 && !ifCityInTabu(m, k)){cityProb[c].num = m;cityProb[c].prob = citySelProb(k, m);c++;}}//2、线性化选择概率for (int m = 0; m < c; m++){for (int n = m; n >= 0; n--){lineCityProb[m] += cityProb[n].prob;}}//3、产生随机数选择城市double r = rand() / double(RAND_MAX);int j = 0;   //选取的目标城市for (int m = 0; m < cityNum; m++){if (r <= lineCityProb[m]){j = cityProb[m].num;updateAnt(k, j);if (j == f)ants[k].flag = 1;  //若蚂蚁k下一步城市为目的地城市,则修改标志return j;}}
}

信息素更新

因为将信息素存入矩阵,所以在计算时较为简单,具体分为如下几步:

  1. 计算信息素增量矩阵:
    for k = 1 to m do (遍历蚁群)
    for j = 1 to n do (遍历蚂蚁k的行走路径)
       计算蚂蚁k在路径(i, j)对应的信息素增量(见公式(3));
    更新路径(i, j)在上一轮的信息素增量;
      end for
    end for
  2. 计算更新后的信息素矩阵:
    信息素挥发系数*信息素矩阵+信息素增量矩阵(见公式(2))。
    对应代码片如下:
 void updatePher()
{for (int i = 0; i < antNum; i++){if(ants[i].flag == 1)  //只对到达目的点的蚂蚁 所走过路径 更新信息素for (int j = 0; j < pathNum; j++){if (ants[i].antPath[j] == -1 || ants[i].antPath[j + 1] == -1)break;elsenextPher(ants[i].antPath[j], ants[i].antPath[j + 1])+= pQ / getAntLen(ants[i]);}}nextPher = pVol * pher + nextPher;
}

3.2 运行结果

参数设置

const int cityNum = 8;     //城市数量
const int pathNum = 16;    //路径数量
const int antNum = 12;     //蚂蚁数量(1.5倍城市数量)
const double pVol = 0.3;   //信息素挥发系数 0.2~0.5
const int pQ = 10;         //信息素强度 10~1000
const double pImp = 3;     //信息素相对重要性 1~4
const double qImp = 4;     //启发信息相对重要性 3~4.5
const int gen = 100;       //迭代次数 100~500

运行结果

在这里插入图片描述

问题

  1. 各项参数初始值虽然知道设置范围,但因为不够理解参数如何影响迭代的结果,参数设定主要依靠猜测。
  2. 代码运行后,发现回归太早,不符合蚁群算法回归较慢(200~500)的特点,后经过检查,发现是计算蚂蚁k在路径(i,j)上的信息素增量时,将除数Lk理解成了路径(i,j) 的距离,但实际上应该为蚂蚁k本次迭代中做走过路径距离之和。经修改后,可以符合蚁群算法回归较慢的特点。
  3. 只计算源点到某一个定点时,代码没有问题,循环结算到每个顶点最短路径时,有时运行会报如下错误,有时不会,不太明白。
    在这里插入图片描述

源码

#include<iostream>
#include<Eigen\Dense>
#include<stdlib.h>
#include<time.h>
#include<math.h>using namespace Eigen;
using namespace std;/* 功能:此代码使用蚁群算法计算源点0 ~ 其他定点的最短路径author:yuzeweidate:2020/12/19
*/#define CLOCK_PER_SEC ((clock_t)1000)const int cityNum = 8;     //城市数量
const int pathNum = 16;    //路径数量
const int antNum = 12;     //蚂蚁数量(1.5倍城市数量)
const double pVol = 0.3;   //信息素挥发系数 0.2~0.5
const int pQ = 10;         //信息素强度 10~1000
const double pImp = 3;     //信息素相对重要性 1~4
const double qImp = 4;     //启发信息相对重要性 3~4.5
const int gen = 100;       //迭代次数 100~500struct ant                 //蚂蚁结构体
{int loc;               //位置int tabu[cityNum];     //禁忌表int antPath[pathNum];  //走过的路bool flag;             //是否到达终点7
};
struct ant ants[antNum];   //蚁群typedef Matrix<double, 8, 8> Matrix8d;
Matrix8d dist;             //距离矩阵
Matrix8d pher;             //信息素矩阵
Matrix8d nextPher;         //下一代信息素矩阵
Matrix8d insp;             //启发信息矩阵struct city                //城市结构体
{int num;               //编号double prob;           //选择概率
};
struct city cityProb[cityNum];    //可到达城市组
double lineCityProb[cityNum];     //线性化 可到达城市的选择概率clock_t start, finish;     
double duration;void initAnts();                  
void initCityProb();              
void initMarix();   
bool ifCityInTabu(int, int);
int citySelect(int, int);
void updateAnt(int, int);
double citySelProb(int, int);
int getAntLen(ant);
int getBestPath();
void printBestPath(int, int);
void updatePher();
void evolution();int main()
{srand((unsigned)time(NULL));evolution();
}//蚁群初始化
void initAnts()
{//初始化禁忌表与行走路线for (int i = 0; i < antNum; i++){for (int j = 0; j < cityNum; j++){ants[i].tabu[j] = -1;}for (int j = 0; j < pathNum; j++){ants[i].antPath[j] = -1;}}//将蚂蚁放入城市for (int i = 0; i < antNum; i++){//ants[i].loc = rand() % 8;ants[i].loc = 0;//出发点都在起点ants[i].tabu[0] = ants[i].loc;ants[i].antPath[0] = ants[i].loc;ants[i].flag = 0;}
}//初始化城市选择概率数组
void initCityProb()
{for (int i = 0; i < cityNum; i++){cityProb[i].num = -1;cityProb[i].prob = 0;lineCityProb[i] = 0;}
}//初始化距离、信息素、启发信息矩阵
void initMarix()
{dist = Matrix8d::Constant(8, 8, -1);dist(0, 2) = 47;dist(0, 4) = 70;dist(0, 5) = 24;dist(1, 3) = 31;dist(1, 6) = 74;dist(1, 7) = 79;dist(2, 1) = 55;dist(2, 3) = 88;dist(2, 4) = 23;dist(2, 6) = 66;dist(3, 7) = 29;dist(4, 1) = 31;dist(4, 6) = 42;dist(5, 2) = 25;dist(5, 3) = 120;dist(6, 7) = 66;pher = Matrix8d::Zero();nextPher = Matrix8d::Zero();insp = Matrix8d::Zero();for (int i = 0; i < 8; i++){for (int j = 0; j < 8; j++){if (dist(i, j) != -1){insp(i, j) = 1 / dist(i, j);//启发信息为距离的倒数pher(i, j) = 1;             //信息素浓度初始值为1}}}
}//轮盘赌选择下一步行进城市
int citySelect(int k, int f)
{int c = 0;//记录蚂蚁可行进的城市个数//1、计算可行进的各城市 选择概率for (int m = 0; m < cityNum; m++){//若城市(i,j)之间有路且j不在蚂蚁k的禁忌表中,则计算概率if (dist(ants[k].loc, m) != -1 && !ifCityInTabu(m, k)){cityProb[c].num = m;cityProb[c].prob = citySelProb(k, m);c++;}}//2、线性化选择概率for (int m = 0; m < c; m++){for (int n = m; n >= 0; n--){lineCityProb[m] += cityProb[n].prob;}}//3、产生随机数选择城市double r = rand() / double(RAND_MAX);int j = 0;   //选取的目标城市for (int m = 0; m < cityNum; m++){if (r <= lineCityProb[m]){j = cityProb[m].num;updateAnt(k, j);if (j == f)ants[k].flag = 1;  //若蚂蚁k下一步城市为目的地城市,则修改标志return j;}}
}//更新蚂蚁信息
void updateAnt(int k, int l)
{ants[k].loc = l;for (int i = 0; i < cityNum; i++)if (ants[k].tabu[i] == -1){ants[k].tabu[i] = l;break;}for (int i = 0; i < pathNum; i++)if (ants[k].antPath[i] == -1){ants[k].antPath[i] = l;break;}
}//蚂蚁k从当前城市i选择下一步行进城市为j市的概率
double citySelProb(int k, int j)
{double a, b, c, prob;a = b = c = prob = 0;int i = ants[k].loc;a = pow(pher(i, j), pImp) + pow(insp(i, j), qImp);for (int m = 0; m < cityNum; m++){if (dist(i, m) != -1 && !ifCityInTabu(m, k)){b = pow(pher(i, m), pImp) + pow(insp(i, m), qImp);c += b;}}prob = a / c;return prob;
}//判断城市j是否在蚂蚁k的禁忌表中
bool ifCityInTabu(int j, int k)
{for (int i = 0; i < cityNum; i++){if (j == ants[k].tabu[i]){return 1;//break;}}return 0;
}//计算路径长度
int getAntLen(struct ant a)
{int len = 0;for (int j = 0; j < pathNum; j++){if (a.antPath[j] == -1 || a.antPath[j + 1] == -1)break;elselen += dist(a.antPath[j], a.antPath[j + 1]);}return len;
}//计算最优路径对应的蚂蚁编号
int getBestPath()
{int d[antNum];int min;int k;  //蚂蚁k的路线到达目的地节点最短for (int i = 0; i < antNum; i++){d[i] = -1;}for (int i = 0; i < antNum; i++){d[i] = getAntLen(ants[i]);}min = d[0];k = 0;for (int i = 1; i < antNum; i++){if (d[i] < min && ants[i].flag == 1)  // 最优路径只从到达目标点的蚂蚁中筛选{min = d[i];k = i;}}return k;
}//打印最优路径、最短距离
void printBestPath(int k, int f)
{cout << "  最短路径为:";for (int i = 0; i < pathNum; i++){if (ants[k].antPath[i] == -1)break;cout << ants[k].antPath[i];if (ants[k].antPath[i+1] != -1)cout << "->";}cout << endl;cout << "  对应距离为:" << getAntLen(ants[k]) << endl;
}//更新信息素矩阵
void updatePher()
{for (int i = 0; i < antNum; i++){if(ants[i].flag == 1)  //只对到达目的点的蚂蚁 所走过路径 更新信息素for (int j = 0; j < pathNum; j++){if (ants[i].antPath[j] == -1 || ants[i].antPath[j + 1] == -1)break;elsenextPher(ants[i].antPath[j], ants[i].antPath[j + 1])+= pQ / getAntLen(ants[i]);}}nextPher = pVol * pher + nextPher;
}//迭代
void evolution()
{for (int f = 1; f < cityNum; f++){cout << "【从源点0到定点" << f << "】" << endl;cout << "开始迭代........." << endl;//初始化参数initAnts();initMarix();int g = 0; //当前代数start = clock();while (g < gen){//1、蚁群内所有蚂蚁都到达目的地int p = 0; //蚁群前进步数while (p < pathNum){for (int i = 0; i < antNum; i++){if (ants[i].flag == 1)//到达目的地continue;citySelect(i, f);initCityProb();}p++;}if (g == gen - 1){cout << "达到最高迭代次数!" << endl;printBestPath(getBestPath(), f);}//3、更新信息素矩阵updatePher();//4、初始化蚁群;更新信息素矩阵initAnts();pher = nextPher;nextPher = Matrix8d::Zero();g++;}finish = clock();duration = ((double)finish - start) / CLOCK_PER_SEC;cout << "  耗时:" << duration << "秒" << endl;}}

http://chatgpt.dhexx.cn/article/Vkd5GyPM.shtml

相关文章

10分钟搞懂蚁群算法

蚂蚁几乎没有视力&#xff0c;但他们却能够在黑暗的世界中找到食物&#xff0c;而且能够找到一条从洞穴到食物的最短路径。它们是如何做到的呢&#xff1f; 蚂蚁寻找食物的过程 单只蚂蚁的行为及其简单&#xff0c;行为数量在10种以内&#xff0c;但成千上万只蚂蚁组成的蚁群却…

蚁群算法的简单理解

蚁群优化算法是意大利学者等人在世纪年代初提出的一种源于生物世界的新型启发式仿生算法。它是从自然界中蚂蚁觅食过程的协作方式得到启发而研究产生的。 在自然界中&#xff0c;蚁群可以在其觅食的过程中逐渐寻找到食物源与巢穴之间的最短路径。单个蚂蚁在运动过程中能够分泌…

蚁群算法原理及matlab代码实现

蚁群算法基本原理&#xff1a; 背景&#xff1a; 在自然界中&#xff0c;生物群体所表现出的智能得到越来越多的关注&#xff0c;许多的群智能优化算法都是通过对群体智能的模拟而实现的。其中模拟蚂蚁群体觅食的蚁群算法成为一种主要的群智能算法。 算法原理&#xff1a; 在…

蚁群算法介绍

前言&#xff1a;本篇文章主要讲述蚁群算法以及相关算法的matlab实现 一、蚁群算法 蚁群算法是在20世纪90年代由澳大利亚学者Marco Dorigo等人通过观察蚁群觅食的过程&#xff0c;发现众多蚂蚁在寻找食物的过程中&#xff0c;总能找到一条从蚂蚁巢穴到食物源之间的最短路径。随…

优化算法3--蚁群算法(原理)

1 算法简介 优化问题在科学和工业领域都非常重要。这些优化问题的实际例子有时间表调度、护理时间分配调度、列车调度、容量规划、旅行商问题、车辆路径问题、群店调度问题、组合优化等。为此&#xff0c;开发了许多优化算法。蚁群优化就是其中之一。 蚁群优化(Ant colony op…

蚁群算法(实例帮助理解)

1. 算法简介1.1 算法起源1.2 算法应用 2. 基本原理3. 算法设计3.1 算法步骤3.2 参数意义及设置3.3 构建路径3.4 更新信息素浓度3.5 判断是否中止 4. 实例演示&#xff08;TSP问题&#xff09; 1. 算法简介 1.1 算法起源 蚁群算法(ant colony optimization, ACO)&#xff0c;又…

蚂蚁算法蚁群算法-原理-思路-步骤-程序实现

蚂蚁算法蚁群算法-原理-思路-步骤-程序实现 ❀算法介绍 历史 蚁群优化算法是一种用来在图中寻找优化路径的机率型算法。它由Marco Dorigo于1992年在他的博士论文中提出&#xff0c;其灵感来源于蚂蚁在寻找食物过程中发现路径的行为。蚁群算法是一种模拟进化算法&#xff0c;…

蚁群算法原理及其实现(python)

蚁群算法(AG)是一种模拟蚂蚁觅食行为的模拟优化算法&#xff0c;它是由意大利学者Dorigo M等人于1991年首先提出&#xff0c;并首先使用在解决TSP&#xff08;旅行商问题&#xff09;上。 之后&#xff0c;又系统研究了蚁群算法的基本原理和数学模型. 蚁群算法的基本思想: 蚁群…

智能算法——蚁群算法

1、原理 蚁群算法是受到对真实蚂蚁群觅食行为研究的启发而提出。生物学研究表明&#xff1a;一群相互协作的蚂蚁能够找到食物和巢穴之间的最短路径,而单只蚂蚁则不能。生物学家经过大量细致观察研究发现,蚂蚁个体之间的行为是相互作用相互影响的。蚂蚁在运动过程中,能够在它所…

蚁群算法理解与实现

蚁群算法&#xff0c;也是优化算法当中的一种。蚁群算法擅长解决组合优化问题。蚁群算法能够有效的解决著名的旅行商问题&#xff08;TSP&#xff09;&#xff0c;不止如此&#xff0c;在其他的一些领域也取得了一定的成效&#xff0c;例如工序排序问题&#xff0c;图着色问题&…

蚁群算法(ACO)学习笔记

蚁群算法笔记 最近阅读论文&#xff0c;提到几种常见的搜索算法&#xff0c;于是对比学习一下。本文转载数据之巅大神文章对蚁群算法进行简单介绍&#xff0c;并用C语言编码实现蚁群算法来解决旅行商&#xff08;TSP&#xff09;问题。 1 蚁群算法基本原理 1.1 算法综述 对于…

【智能算法第一期】蚁群算法原理和多种改进方法

1. 什么是蚁群算法&#xff1f; 蚁群算法的本身来源于一种生物的自然现象&#xff0c;即蚂蚁在寻找食物过程中发现路径的行为&#xff0c;是一种模拟进化的算法。蚁群算法的寻优快速性是由通过正反馈式的信息传递和积累来实现的&#xff0c;分布式计算特征可以避免算法的早熟收…

蚁群算法

文章目录 一、蚁群算法原理二、蚁群算法参数改变测试 一、蚁群算法原理 蚁群算法(AG)是一种模拟蚂蚁觅食行为的模拟优化算法&#xff0c;它是由意大利学者Dorigo M等人于1991年首先提出&#xff0c;并首先使用在解决TSP&#xff08;旅行商问题&#xff09;上。之后&#xff0c…

蚁群算法详解

1、算法背景及原理 蚁群算法是一种智能优化算法&#xff0c;在TSP商旅问题上得到广泛使用。蚁群算法于1992年由Marco Dorigo首次提出&#xff0c;该算法来源于蚂蚁觅食行为。由于蚂蚁没有视力&#xff0c;所以在寻找食物源时&#xff0c;会在其经过的路径上释放一种信息素&…

Linux:详解 用户,用户组的解释创建等。

文章目录 Linux中用户和组的类型1、Linux下的用户可以分为三类2、Linux中的组有以下两类3、Linux中用户和用户组的配置文件&#xff08;1&#xff09;用户账号文件——/etc/passwdpasswd&#xff08;2&#xff09;用户密码文件——/etc/shadow&#xff08;3&#xff09;用户组账…

linux用户和用户组权限

Linux常规操纵 : 多用户操作 1.1 linux的用户与用户组理论 1.1.1 概述 Linux是一个真实的、完整的多用户多任务操作系统,多用户多任务就是可以在系统上建立多个用户,而多个用户可以在同一时间内登录同一个系统执行各自不同的任务,而互不影响。 root :系统维护 www:网页…

将用户添加到docker用户组

普通用户使用docker命令的时候经常会提示权限不足 Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.26/containers/json: dial unix /var/run/docker.sock: connect: …

linux添加用户和用户组

原文地址&#xff1a;linux添加用户和用户组 – 自我的进化http://www.shanxing.top/?p181 用户 创建用户&#xff1a;useradd <用户名> 设置密码&#xff1a;passwd <用户名>删除用户&#xff1a;userdel <用户名> 用户组&#xff1a; 新建用户组&#x…

用户,用户组与权限

一.用户与用户组 1.用户的分类 root用户:系统唯一,真实,可登录系统,可操作系统任何文件的用户,拥有最高权限 虚拟用户:这类用户被称为伪用户,不具有登录能力,但是系统不可缺少这类用户,例如bin,daemon,ssh等,一般是系统创建,也可手动创建 普通用户:具有登录能力,但是只能操作…

重拾Linux(三)用户和用户组管理

Linux是一个多用户多任务的操作系统&#xff0c;任何一个想要使用系统资源的用户&#xff0c;都必须向系统管理员申请一个账号&#xff0c;然后用这个账号的身份进入系统。每创建一个账号&#xff0c;如果没有指定新增用户的家目录&#xff0c;则会在 /home 目录下创建一个和新…