swarm: a large group of insects all moving together.
个体:群中的成员,之间是平等关系,没有主从关系。
个体仅具有简单智能,群体行为表现出较高级的智能。
典型的优化算法:蚁群算法、粒子群算法。还有其他的算法:鱼群算法、蜂群算法、蛙跳算法、萤火虫算法、细菌觅食算法等。
算法 | 大概内容 | 概括 |
---|---|---|
蚁群优化算法 | 蚂蚁如何在食物源和巢穴之间找到最短路径 | 路径选择;信息素更新;协同工作 |
粒子群优化算法 | 鸟群随机搜索食物 | 个体经验;社会学习 |
人工鱼群算法 | 鱼在水域的游动 | 觅食行为;追尾行为;聚群行为;随机游动 |
1991年Dorigo解决旅行商问题。改进衍生:蚁群系统,最大最小蚂蚁系统,最优保留蚁群系统。
返回:蚂蚁沿着一条路到达终点后会马上返回。
信息素:信息素多表示经过这里的蚂蚁多,因而会有更多的蚂蚁聚集过来。
正反馈:某一路径上走过的蚂蚁越多,后来者选择该路径的概率越大。
以解决100个城市的TSP问题为例。
// ACO.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
unsigned seed = (unsigned)time(0);
//城市数目
#define CITY_NUM 100
//蚁群规模
#define ANT_NUM 150
//迭代最大次数
#define TMAX 1000
double CityPos[CITY_NUM][2] = {
{18200.0000, 109550.0000},
{18200.0000, 109583.3333},
{18206.3889, 109581.9444},
{18207.5000, 109477.7778},
{18215.8333, 109700.5556},
{18216.6667, 109700.0000},
{18220.5556, 109510.2778},
{18223.8889, 109552.2222},
{18229.7222, 109528.3333},
{18233.3333, 109533.3333},
{18233.3333, 109616.6667},
{18233.8889, 109703.8889},
{18236.6667, 109625.0000},
{18243.0556, 109505.0000},
{18243.6111, 109690.2778},
{18245.2778, 109373.8889},
{18246.6667, 109559.7222},
{18250.0000, 109516.6667},
{18250.0000, 109583.3333},
{18257.7778, 109689.4444},
{18260.5556, 109712.7778},
{18263.0556, 109580.8333},
{18263.0556, 109679.7222},
{18265.0000, 109638.6111},
{18266.6667, 109483.3333},
{18266.6667, 109566.6667},
{18266.6667, 109666.6667},
{18271.3889, 109705.8333},
{18278.3333, 109730.2778},
{18279.4444, 109675.2778},//30个
{18281.1111, 109480.8333},
{18281.3889, 109684.1667},
{18283.3333, 109400.0000},
{18283.8889, 109569.7222},
{18283.8889, 109705.5556},
{18284.4444, 109661.6667},
{18296.9444, 109611.6667},
{18302.2222, 109210.0000},
{18303.8889, 109432.2222},
{18304.1667, 109528.3333},
{18304.4444, 109335.2778},
{18304.4444, 109391.1111},
{18307.2222, 109144.1667},
{18314.7222, 109269.7222},
{18315.2778, 109626.6667},
{18316.6667, 109166.6667},
{18316.6667, 109266.6667},
{18317.2222, 109331.6667},
{18319.1667, 109442.2222},
{18319.7222, 109705.0000},//50个
{18320.2778, 109173.6111},
{18321.6667, 109551.1111},
{18325.0000, 109673.3333},
{18325.8333, 109528.3333},
{18327.2222, 109256.3889},
{18327.7778, 109247.5000},
{18332.5000, 109490.2778},
{18333.3333, 109450.0000},
{18335.2778, 109323.0556},
{18336.1111, 109731.3889},
{18344.7222, 109452.2222},
{18347.2222, 109638.8889},
{18347.7778, 109203.3333},
{18347.7778, 109587.7778},
{18349.1667, 109440.8333},
{18351.3889, 109725.8333},
{18351.3889, 109726.6667},
{18355.5556, 109627.2222},
{18356.1111, 109126.6667},
{18358.6111, 109126.3889},
{18359.1667, 108988.6111},
{18362.7778, 109602.2222},
{18370.5556, 109099.7222},
{18370.8333, 109005.5556},
{18371.6667, 109508.8889},
{18372.7778, 109163.6111},
{18374.7222, 109244.4444},
{18375.5556, 109162.2222},
{18376.1111, 109035.2778},
{18378.0556, 109603.3333},
{18378.0556, 109742.5000},
{18378.6111, 109641.6667},
{18388.3333, 109824.7222},
{18392.2222, 109725.0000},
{18393.6111, 109430.8333},
{18397.7778, 109987.5000},
{18398.6111, 109496.3889},
{18400.0000, 109730.2778},
{18400.0000, 109750.0000},
{18400.8333, 109202.7778},
{18402.2222, 109283.0556},
{18403.6111, 109020.8333},
{18403.6111, 109868.8889},
{18404.7222, 110018.6111},
{18406.6667, 109616.6667},
{18408.6111, 109758.3333},
{18409.4444, 109676.3889},
{18414.1667, 110070.2778},
{18415.8333, 108933.8889},
{18415.8333, 109725.0000}//100个
};
//alpha参数
#define ALPHA 3
//beta参数
#define BETA 4
//rho参数
#define RHO 0.4
//Q参数
#define Q 100
//地图
const int maxn = 100;
//距离矩阵
double dis[maxn][maxn];
//信息素矩阵
double info[maxn][maxn];
//启发因子矩阵
double E[maxn][maxn];
//
int vis[CITY_NUM][CITY_NUM];
//最佳结果
double BestLength;
double ans[CITY_NUM];
const double mmax = 10e9;
//产生随机整数
//指定范围
int rnd(int nLow, int nUpper)
{
return nLow + (nUpper - nLow) * rand() / (RAND_MAX + 1);
}
//产生随机浮点数
//指定范围
double rnd(double dbLow, double dbUpper)
{
double dbTemp = rand() / ((double)RAND_MAX + 1.0);
return dbLow + dbTemp * (dbUpper - dbLow);
}
//浮点数取整
//四舍五入
double ROUND(double dbA)
{
return (double)((int)(dbA + 0.5));
}
//ant
struct Ant
{
//蚂蚁走的路线,时间顺序,存放内容是“第i步到了哪个城市”
int Path[CITY_NUM];
//路径的总长度
double length;
//标记走过的城市,城市标记表,如果走过了记为1,否则都是0
int vis[CITY_NUM];
//当前所处的城市编号
int cur_cityno;
//已走城市的数量,会累加
int moved_cnt;
//初始化函数
void Init()
{
//开辟空间
memset(vis, 0, sizeof(vis));
//路径总长度初始化为0
length = 0;
//随便定一个起始城市
cur_cityno = rnd(0, CITY_NUM);
//路线记录的第一个城市设为刚才random出来的城市
Path[0] = cur_cityno;
//在记录城市是否已经走过的数组中标记刚才random出来的城市为1
vis[cur_cityno] = 1;
//已经走了一个城市
moved_cnt = 1;
}
//选择路径
//求出蚂蚁要走的下一个城市的编号为多少
int chooseNextCity()
{
//返回的城市编号
//初始化设置为-1(后续再进行改变)
int nSelectedCity = -1;
//计算当前城市和没去过的城市之间的信息素总量
double dbTotal = 0.0;
//数组
//存放城市被选中的概率,也就是公式中的pk(i,j)中分子的部分
double prob[CITY_NUM];
//转换公式
//对于每个城市而言
for (int i = 0; i < CITY_NUM; i++)
{
//如果一直以来都没有访问过编号为i的城市
if (!vis[i])
{
//求分子
prob[i] = pow(info[cur_cityno][i], ALPHA) * pow(1.0 / dis[cur_cityno][i], BETA);
dbTotal = dbTotal + prob[i];
}
else
{
prob[i] = 0;
}
}
//轮盘赌选择
double dbTemp = 0.0;
//如果总的信息素值大于0
if (dbTotal > 0.0)
{
//在0和信息素总含量中随机生成一个阈值
dbTemp = rnd(0.0, dbTotal);
for (int i = 0; i < CITY_NUM; i++)
{
if (!vis[i])
{
//作差
dbTemp = dbTemp - prob[i];
//如果该城市的信息素含量超过随机生成的阈值大小
if (dbTemp < 0.0)
{
//那么选择该城市
nSelectedCity = i;
//跳出循环
break;
}
}
}
}
//如果经过轮盘赌还是没选出下一步走哪个城市
if (nSelectedCity == -1)
{
//在所有城市当中选出第一个没去过的城市作为下一步要去的城市
for (int i = 0; i < CITY_NUM; i++)
{
//遇到第一个没有被访问的城市
if (!vis[i])
{
//选择该城市
nSelectedCity = i;
//跳出循环
break;
}
}
}
return nSelectedCity;
}
//蚂蚁移动
void Move()
{
//首先找到接下来要去哪个城市
int nCityno = chooseNextCity();
//蚂蚁下一步要走这个城市
Path[moved_cnt] = nCityno;
//蚂蚁即将经历这个城市
vis[nCityno] = 1;
//目前到达这个城市
cur_cityno = nCityno;
//蚂蚁的总路线登记累加move的距离
length = length + dis[Path[moved_cnt - 1]][Path[moved_cnt]];
moved_cnt++;
}
//蚂蚁搜索----总流程
void Search()
{
//先初始化一只蚂蚁
Init();
//蚂蚁在地图上走
while (moved_cnt < CITY_NUM)
{
Move();
}
//补上终点和起点的路径长度
length = length + dis[Path[CITY_NUM - 1]][Path[0]];
}
};
struct TSP
{
//数组
//存放一群蚂蚁
Ant ants[ANT_NUM];
//记录最好结果的蚂蚁信息
Ant ant_best;
void Init()
{
//初始设置这群蚂蚁中最好的距离是一个超大值
//等待迭代后进行更新
ant_best.length = mmax;
//初始化城市间距离矩阵
//遍历计算,邻接矩阵存放城市之间的欧式距离
//dis二维数组
for (int i = 0; i < CITY_NUM; i++)
{
for (int j = 0; j < CITY_NUM; j++)
{
double temp1 = CityPos[j][0] - CityPos[i][0];
double temp2 = CityPos[j][1] - CityPos[i][1];
dis[i][j] = sqrt(temp1 * temp1 + temp2 * temp2);
}
}
//初始化信息素
//info二维数组
for (int i = 0; i < CITY_NUM; i++)
{
for (int j = 0; j < CITY_NUM; j++)
{
info[i][j] = 1.0;
}
}
}
//信息素矩阵更新
void Updateinfo()
{
//信息素增量矩阵
double tmpinfo[CITY_NUM][CITY_NUM];
//
memset(tmpinfo, 0, sizeof(tmpinfo));
//城市m,初始值设为0
int m = 0;
//城市n,初始值设为0
int n = 0;
//
for (int i = 0; i < ANT_NUM; i++)
{
//从第一个城市到最后一个城市
for (int j = 1; j < CITY_NUM; j++)
{
m = ants[i].Path[j];
n = ants[i].Path[j - 1];
//计算信息素增量
tmpinfo[n][m] = tmpinfo[n][m] + Q / ants[i].length;
//保持信息素增量矩阵的对称性
tmpinfo[m][n] = tmpinfo[n][m];
}
//最后一个城市到第一个城市
n = ants[i].Path[0];
//计算信息素增量
tmpinfo[n][m] = tmpinfo[n][m] + Q / ants[i].length;
//保持信息素增量矩阵的对称性
tmpinfo[m][n] = tmpinfo[n][m];
}
//原信息素矩阵耗散后的值加上信息素增量矩阵对应的值
for (int i = 0; i < CITY_NUM; i++)
{
for (int j = 0; j < CITY_NUM; j++)
{
info[i][j] = info[i][j] * RHO + tmpinfo[i][j];
}
}
}
//寻找路径----总流程
void Search()
{
//进行TMAX次循环
//里面是每次循环的内容
for (int i = 0; i < TMAX; i++)
{
cout << "当前循环次数为" << i << endl;
//对于当前设定的种族中的所有蚂蚁而言,都开始分别进行路线搜索
//并且完成一次搜索
for (int j = 0; j < ANT_NUM; j++)
{
ants[j].Search();
}
//记录最优结果
for (int j = 0; j < ANT_NUM; j++)
{
//希望找到最短距离
if (ant_best.length > ants[j].length)
{
//更新
ant_best = ants[j];
}
}
//更新信息素
Updateinfo();
cout << "目前得到的最短路径长度为" << ant_best.length << endl;
}
}
};
int main()
{
srand(seed);
TSP tsp;
tsp.Init();
tsp.Search();
cout << "最短路径为" << endl;
for (int i = 0; i < CITY_NUM; i++)
{
cout << tsp.ant_best.Path[i] << endl;
}
return 0;
}
// Run program: Ctrl + F5 or Debug > Start Without Debugging menu
// Debug program: F5 or Debug > Start Debugging menu
// Tips for Getting Started:
// 1. Use the Solution Explorer window to add/manage files
// 2. Use the Team Explorer window to connect to source control
// 3. Use the Output window to see build output and other messages
// 4. Use the Error List window to view errors
// 5. Go to Project > Add New Item to create new code files, or Project > Add Existing Item to add existing code files to the project
// 6. In the future, to open this project again, go to File > Open > Project and select the .sln file