在城市 r r r上的蚂蚁通过该规则选择下一个城市 s s s, s = { arg max u ∈ J k ( r ) { [ τ ( r , u ) ] ⋅ [ η ( r , u ) ] β } , if q ≤ q 0 (exploitation) S , otherwise(biased exploration) s= \begin{cases}\arg \max_{u\in J_k(r)}\{[\tau(r,u)]\cdot[\eta(r,u)]^{\beta}\}, & \text {if $q\leq q_0$(exploitation)} \\ S, & \text{otherwise(biased exploration)} \end{cases} s={argmaxu∈Jk(r){[τ(r,u)]⋅[η(r,u)]β},S,if q≤q0(exploitation)otherwise(biased exploration) q q q是均匀分布, q 0 q_0 q0是一个参数, S S S是随机从以下分布(给出在城市 r r r的蚂蚁 k k k选择去城市 s s s的概率)中采样的值, p k ( r , s ) = { [ τ ( r , s ) ] ⋅ [ η ( r , s ) ] β ∑ u ∈ J k ( r ) [ τ ( r , u ) ] ⋅ [ η ( r , u ) ] β if s ∈ J k ( r ) 0 , otherwise p_k(r,s)= \begin{cases}\ \frac{[\tau(r,s)]\cdot[\eta(r,s)]^{\beta}}{\sum_{u\in J_k(r)}[\tau(r,u)]\cdot[\eta(r,u)]^\beta}\, & \text {if $s\in J_k(r)$} \\ 0, & \text{otherwise} \end{cases} pk(r,s)=⎩⎨⎧ ∑u∈Jk(r)[τ(r,u)]⋅[η(r,u)]β[τ(r,s)]⋅[η(r,s)]β0,if s∈Jk(r)otherwise
在ACS中,仅允许最短行程的蚂蚁存放信息素,故全局更新规则如下, τ ( r , s ) = ( 1 − α ) ⋅ τ ( r , s ) + α ⋅ Δ τ ( r , s ) \tau(r,s)=(1-\alpha)\cdot\tau(r,s)+\alpha \cdot \Delta \tau(r,s) τ(r,s)=(1−α)⋅τ(r,s)+α⋅Δτ(r,s)其中, Δ τ ( r , s ) = { ( L g b ) − 1 if ( r , s ) ∈ global-best-tour 0 otherwise \Delta \tau(r,s)=\begin{cases}(L_{gb})^{-1}&\text {if$(r,s)\in$global-best-tour} \\ 0&\text{otherwise}\end{cases} Δτ(r,s)={(Lgb)−10if(r,s)∈global-best-tourotherwise L g b L_{gb} Lgb表示从实验开始后的全局最佳路径, 0 < α < 1 0<\alpha<1 0<α<1是一个参数
每只蚂蚁在游览途中,通过应用局部更新规则来访问边并更改信息素水平 τ ( r , s ) = ( 1 − ρ ) ⋅ τ ( r , s ) + ρ ⋅ Δ τ ( r , s ) \tau(r,s)=(1-\rho)\cdot \tau(r,s)+\rho \cdot \Delta \tau(r,s) τ(r,s)=(1−ρ)⋅τ(r,s)+ρ⋅Δτ(r,s)其中 0 < r < 1 0
//主要是规则公式中的一些常量
#define m 10//蚂蚁数量为10
#define alpha 0.1//α,为0.1
#define beta 2
#define q0 0.9
#define rho 0.1//ρ
//蚂蚁类
class ant{
public:
int localcity;//该蚂蚁的当前城市
int nextcity;//该蚂蚁的下一个城市
vector<int> tour;//该蚂蚁的路径,每到一个城市就将这个城市push_back到tour里
set<int> unvisited;//存储该蚂蚁未访问的城市,使整个solution符合现实情况
int length;//对应tour的长度
};
ant ants[m+1];//蚁群,蚂蚁1到蚂蚁m
//全局变量
const int citys_num=76;//城市数量
double citys_x[citys_num+1];//存放城市的x坐标
double citys_y[citys_num+1];//存放城市的y坐标
int D[citys_num+1][citys_num+1];//距离矩阵,D[i][j]存放城市i到城市j的距离
double tao[citys_num+1][citys_num+1];//τ,信息素矩阵
double tao0;//τ0=(n*Lnn)^(-1)
vector<int> tour_gb;//全局最佳路径
int tour_length_gb= INT_MAX;//全局最佳路程,初始化为无穷大
没有实现对所有格式文件的读入,具体读入需要根据问题的数据格式修改函数。
例如对kroA100,先跳过前六行,之后逐行读入每个城市的编号、x坐标、y坐标,然后计算距离矩阵
//读取TSP文件中的TSP问题的城市数据
void ReadTSPData(){
ifstream infile;
infile.open("D:\\2019SRP\\TSP数据\\ALL_tsp\\eil76.tsp\\eil76.tsp");
for(int i=0;i<6;i++){
string trash;
getline(infile,trash);
}//过滤掉前六行的文件信息
//开始读入有用数据
for(int i=1;i<=citys_num;i++){
int t1;
double t2,t3;
infile>>t1>>t2>>t3;
citys_x[i]=t2;citys_y[i]=t3;//存入城市的x、y值、
}
//计算城市间的距离矩阵
for(int i=1;i<=citys_num;i++){
for(int j=i+1;j<=citys_num;j++){
D[i][j]=round_double(sqrt((citys_x[i]-citys_x[j])*(citys_x[i]-citys_x[j])+(citys_y[i]-citys_y[j])*(citys_y[i]-citys_y[j])));
D[j][i]=D[i][j];//对称TSP
}
D[i][i]=0;//自己到自己的距离为0
}
}
初始化蚂蚁A,设其起点为城市1,对其应用就近原则,然后通过得到的路程计算 τ 0 \tau_0 τ0
void Calcu_tao0(){
double Lnn=0;
ant A;//通过蚂蚁A来计算出Lnn,Lnn标识按照优先选取最近城市的原则对所有城市做遍历后得到的一个回路的长度
A.length=0;A.localcity=0;A.tour.clear();A.unvisited.clear();
for(int i=1;i<=citys_num;i++){A.unvisited.insert(i);}
//初始化蚂蚁A
A.localcity=1;A.tour.push_back(1);A.unvisited.erase(1);//设蚂蚁A的起点为城市1(?)
//对蚂蚁A Build_Tour(最近原则)
for(int i=2;i<=citys_num;i++){
auto iter=A.unvisited.begin();
int nearest_city= *iter;
double nearest_len=D[A.localcity][nearest_city];
while(iter!=A.unvisited.end()){
if(D[A.localcity][*iter]<nearest_len){
nearest_city=*iter;
nearest_len=D[A.localcity][*iter];
}
iter++;
}
//至此,找出了在A.unvisited集合中离A.localcity最近的城市nearest_city和到其的路程nearest_len
A.length+=nearest_len;A.localcity=nearest_city;A.tour.push_back(nearest_city);A.unvisited.erase(nearest_city);
//将nearest_city加入到A的tour中
}
A.tour.push_back(1);A.length+=D[A.localcity][1];A.localcity=1;//蚂蚁A需要回到起始城市1
Lnn=A.length;
tao0=1/(citys_num*Lnn);//计算出tao0
}
//初始化信息素矩阵
void Initial_tao(){
Calcu_tao0();//计算出τ0
//初始化信息素矩阵
for(int i=1;i<=citys_num;i++){
for(int j=1;j<citys_num;j++){
//初始化τ为τ0
tao[i][j]=tao0;
}
}
}
//初始化蚂蚁
void Initial_ants(){
//对每只蚂蚁清空之前记录,主要的有清空tour,对unvisited填满
for(int k=1;k<=m;k++){
ants[k].localcity=0;
ants[k].tour.clear();
ants[k].unvisited.clear();
for(int i=1;i<=citys_num;i++){
ants[k].unvisited.insert(i);
}
ants[k].length=0;
}
//蚂蚁被随机放置,每个城市最多放置一只蚂蚁
vector<int>citys_noants;//没有蚂蚁的城市
for(int i=1;i<=citys_num;i++){
citys_noants.push_back(i);
}//一开始城市都没有蚂蚁
for(int k=1;k<=m;k++){
int Rand=rand()%citys_noants.size();
int c=citys_noants[Rand];//在没有蚂蚁的城市中随机取一
ants[k].tour.push_back(c);//推入蚂蚁的tour
ants[k].localcity=c;//if(k==5){cout<<"c:"<
ants[k].unvisited.erase(c);//蚂蚁的unvisited中删除
citys_noants.erase(citys_noants.begin()+Rand);//从没有蚂蚁的城市集合中剔除
}
}
//判断(r,s)是否位于当前全局最佳路径中
bool IfInL_gb(int startcity,int endcity){
int i;
//全局最佳路径被保存在tour_gb和tour_length_gb中
for(i=0;i<tour_gb.size()-1;i++){
if(tour_gb[i]==startcity)break;
}
if(endcity==tour_gb[i+1]){return true;}
else{return false;}
}
//全局更新
void global_update(){
//遍历当前迭代所有蚂蚁的最佳路程,如果有比全局最佳路程更好的,则替代
for(int k=1;k<=m;k++){
if(ants[k].length<tour_length_gb){
tour_length_gb=ants[k].length;
tour_gb.assign(ants[k].tour.begin(),ants[k].tour.end());
}
}
//应用全局更新规则
for(int i=1;i<=citys_num;i++){
for(int j=1;j<=citys_num;j++){
if(IfInL_gb(i,j)){
tao[i][j]=(1-alpha)*tao[i][j]+alpha*(1/tour_length_gb);//如果属于全局最佳路径
}else{
tao[i][j]=(1-alpha)*tao[i][j];//不属于
}
}
}
}
void Build_Tour(){
for(int i=1;i<= citys_num;i++){//step循环
//决定每个蚂蚁的下一城市
if(i<citys_num){//状态转换——伪随机比例规则
for(int k=1;k<=m;k++){//对于每只蚂蚁
double q=rand()%1000/(double)1000;
if(q<=q0){//exploitation
double pheromone_closeness_max=-1;//要找出最大的[τ(r,u)][η(r,u)]^β
int r=ants[k].localcity;
int s=0;
set<int>::iterator iter=ants[k].unvisited.begin();
double pheromone_closeness=0;
while(iter!=ants[k].unvisited.end()){
int u=*iter;
pheromone_closeness= tao[r][u]*(pow((double)1/D[r][u],(double)beta));
//if(D[r][u]==0){cout<<"D[r][u]:"<
if(pheromone_closeness>pheromone_closeness_max){
s=u;
pheromone_closeness_max=pheromone_closeness;
}
iter++;
}
//if(s==0){cout<<"s:"<
ants[k].nextcity=s;//找出能使[τ(r,u)][η(r,u)]^β最大的u
}else{//biased exploration
double pheromone_closeness_sum=0;
int r=ants[k].localcity;
set<int>::iterator iter=ants[k].unvisited.begin();
while(iter!=ants[k].unvisited.end()){
int u=*iter;
double pheromone_closeness= tao[r][u]*(pow((double)1/D[r][u],(double)beta));
pheromone_closeness_sum+=pheromone_closeness;
iter++;
}
double Rand=rand()%1000/(double)1000;
double temp=0;iter=ants[k].unvisited.begin();
int s=0;
while(temp<=Rand){
int u=*iter;
double pheromone_closeness = tao[r][u]*(pow((double)1/D[r][u],(double)beta));
temp+=pheromone_closeness/pheromone_closeness_sum;
iter++;
s=u;
}
ants[k].nextcity=s;//从random-proportional rule分布(1)中选择的S
}
//至此,对于蚂蚁k(它的当前城市为r),根据伪随机比例规则,从jk(r)中选出了nextcity s。
//if(ants[k].nextcity==0){cout<<"is 0"<
ants[k].tour.push_back(ants[k].nextcity);
ants[k].length+=D[ants[k].localcity][ants[k].nextcity];
ants[k].unvisited.erase(ants[k].nextcity);
ants[k].localcity=ants[k].nextcity;
}
}else{//这时所有城市遍历完,返回起点
//cout<<12121<
for(int k=1;k<=m;k++){//对于每只蚂蚁
//令该蚂蚁返回到原始起点,即下一城市为起点
ants[k].nextcity=ants[k].tour[0];
ants[k].tour.push_back(ants[k].nextcity);
ants[k].length+=D[ants[k].localcity][ants[k].nextcity];
ants[k].localcity=ants[k].nextcity;
}
}
for(int k=1;k<=m;k++){
//应用局部更新规则更新信息素
int r=ants[k].tour[ants[k].tour.size()-2];
int s=ants[k].tour[ants[k].tour.size()-1];
tao[r][s]=(1-rho)*tao[r][s]+rho*tao0;
}
}
}
int main(){
ReadTSPData();//读取TSP数据
Initial_tao();//初始化信息素矩阵
for(int it=0;it<500;it++){//iteration循环
Initial_ants();//初始化蚂蚁
Build_Tour();//每只蚂蚁建立自己的Solution
global_update();//全局更新
cout<<tour_length_gb<<endl;//输出经过每次迭代后的全局最佳路径的长度
}
cout<<"======================================"<<endl;
cout<<"Result:"<<endl;
for(int i=0;i<tour_gb.size();i++){
cout<<tour_gb[i]<<" ";
}cout<<endl;
//输出全局最佳路径
}
这个C++实现能基本遵循ACS的各个步骤,同时运行后也可以看出最佳路径的长度是再不断缩小的,但是仍存在以下问题: