什么是TSP问题?
旅行商问题,即TSP问题(Traveling Salesman Problem)又译为旅行推销员问题、货郎担问题,是数学领域中著名问题之一。假设有一个旅行商人要拜访n个城市,他必须选择所要走的路径,路径的限制是每个城市只能拜访一次,而且最后要回到原来出发的城市。路径的选择目标是要求得的路径路程为所有路径之中的最小值。
蚁群算法的讲解
这个博客讲的不错 点击链接
代码实现
代码参考博客 点击链接
#include<iostream>
#include<stdio.h>
#include<string>
#include<string.h>
#include<cmath>
#include<ctime>
#include<stdlib.h>
using namespace std;
int seed=(int)time(0);//产生随机种子
int CityPos[30][2]= {{87,7},{91,38},{83,46},{71,44},{64,60},{68,58},{83,69},{87,76},{74,78},{71,71},{58,69},{54,62},{51,67},{37,84},{41,94},{2,99},{7,64},{22,60},{25,62},{18,54},{4,50},{13,40},{18,40},{24,42},{25,38},{41,26},{45,21},{44,35},{58,35},{62,32}};
#define CITY_NUM 30//城市数量
#define ANT_NUM 30//蚁群数量
#define TMAC 10000//迭代最大次数
#define ROU 0.5//误差大小
#define ALPHA 1//信息素重要程度的参数
#define BETA 4//启发式因子重要程度的参数
#define Q 100//信息素残留参数
#define maxn 100
#define inf 0x3f3f3f3f
double dis[maxn][maxn];//距离矩阵
double info[maxn][maxn];//信息素矩阵
bool vis[CITY_NUM][CITY_NUM];//标记矩阵
//返回指定范围内的随机整数
int rnd(int low,int upper)
{
return low+(upper-low)*rand()/(RAND_MAX+1);
}
//返回指定范围内的随机浮点数
double rnd(double low,double upper)
{
double temp=rand()/((double)RAND_MAX+1.0);
return low+temp*(upper-low);
}
struct Ant
{
int path[CITY_NUM];//保存蚂蚁走的路径
double length;//路径总长度
bool vis[CITY_NUM];//标记走过的城市
int cur_cityno;//当前城市
int moved_cnt;//已走城市数量
//初始化
void Init()
{
memset(vis,false,sizeof(vis));
length=0;
cur_cityno=rnd(0,CITY_NUM);
path[0]=cur_cityno;
vis[cur_cityno]=true;
moved_cnt=1;
}
//选择下一个城市
int Choose()
{
int select_city=-1;//所选城市编号
double sum=0;
double prob[CITY_NUM];//保存每个城市被选中的概率
for(int i=0; i<CITY_NUM; i++)
{
if(!vis[i])
{
prob[i]=pow(info[cur_cityno][i],ALPHA)*pow(1.0/dis[cur_cityno][i], BETA);
sum=sum+prob[i];
}
else
{
prob[i]=0;
}
}
//进行轮盘选择
double temp=0;
if(sum>0)//总的信息素大于0
{
temp=rnd(0.0,sum);
for(int i=0; i<CITY_NUM; i++)
{
if(!vis[i])
{
temp=temp-prob[i];
if(temp<0.0)
{
select_city=i;
break;
}
}
}
}
else //信息素太少就随便找个没走过的城市
{
for(int i=0; i<CITY_NUM; i++)
{
if(!vis[i])
{
select_city=i;
break;
}
}
}
return select_city;
}
//蚂蚁的移动
void Move()
{
int nex_cityno=Choose();
path[moved_cnt]=nex_cityno;
vis[nex_cityno]=true;
length=length+dis[cur_cityno][nex_cityno];
cur_cityno=nex_cityno;
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 = inf;
//计算两两城市间距离
for (int i = 0; i < CITY_NUM; i++)
{
for (int j = 0; j < CITY_NUM; j++)
{
info[i][j]=1.0;
double temp1=CityPos[j][0]-CityPos[i][0];
double temp2=CityPos[j][1]-CityPos[i][1];
dis[i][j] = sqrt(temp1*temp1+temp2*temp2);
}
}
}
//更新信息素
void UpdateInfo()
{
double temp_info[CITY_NUM][CITY_NUM];
memset(temp_info,0,sizeof(temp_info));
int u,v;
for(int i=0; i<ANT_NUM; i++) //遍历每一只蚂蚁
{
for(int j=1; j<CITY_NUM; j++)
{
u=ants[i].path[j-1];
v=ants[i].path[j];
temp_info[u][v]=temp_info[u][v]+Q/ants[i].length;
temp_info[v][u]=temp_info[u][v];
}
//最后城市和开始城市之间的信息素
u=ants[i].path[0];
temp_info[u][v]=temp_info[u][v]+Q/ants[i].length;
temp_info[v][u]=temp_info[u][v];
}
for(int i=0; i<CITY_NUM; i++)
{
for(int j=0; j<CITY_NUM; j++)
{
info[i][j]=info[i][j]*ROU+temp_info[i][j];
}
}
}
void Search()
{
//迭代TMAC次
for(int i=0; i<TMAC; i++)
{
//所有蚂蚁都进行一次遍历
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();
printf("第%d次迭代最优路径长度是%lf\n", i,ant_best.length);
printf("\n");
}
}
};
int main()
{
srand(seed);
TSP tsp;
tsp.Init();
tsp.Search();
printf("最短路径如下\n");
for(int i=0;i<CITY_NUM;i++)
{
printf("%d",tsp.ant_best.path[i]);
if(i<CITY_NUM-1)
printf("->");
else
printf("\n");
}
return 0;
}