#include "stdafx.h"
#include "string.h"
#include "fstream.h"
#include "iostream.h"
#include "math.h"
#include "time.h"
#include "stdlib.h"
#include "randomc.h" // define classes for random number generators
#include "mersenne.cpp" // members of class TRandomMersenne
#include "iomanip.h"
extern double Q=100,a_para=1,b_para=5,c=8,info_remain=0.6; //酌情改;
//extern int32 seed = time(0); //随机生成种子
extern bool draw=false;
const int Number = 33;
//a_para为公式中的信息素浓度的上标,b_para为可视信息的上标,info_remain为信息素浓度的保留参数,即1-info_remain为挥发度
//c为初始浓度,Q为信息素更新公式中的参数
class city
{
public:
int city_Num,city_index;
double city_x,city_y;
void set_city(int id,double x,double y);
};
class edge
{
public:
int edge_index1,edge_index2;
double edge_density,edge_length;
};
//********************************************************************
class TabuNode
{
public:
int data;
TabuNode *next;
};
class Tabu
{
public:
Tabu();
~Tabu();
int Insert(int &id); //插入已走过的城市节点,1表示插入成功,0表示插入失败
void free(); //遍历一遍后清空链表
bool Inqueue(int id); //判断下一个将要走的节点是否已在链表中,1表示在,0表示不在
bool Isequal(Tabu l1,Tabu l2); //判断2条Tabu链是否相等,1表示相等,0表示不等
// void copy(Tabu &l1,Tabu l2); //将l2链表复制给l1链表
int queue_length(Tabu l1); //返回tabu链表的长度
void print(); //按顺序打印出链表各节点
TabuNode *firstnode,*lastnode;
int Max_length;
};
class AntSystem;
class ant
{
public:
int ant_id;
Tabu antsTabu;
double ComputeLength(AntSystem*);
};
//************************************************************************
class AntSystem
{
public:
//a_para=10,b_para=5,
// double a_para,b_para;
Tabu *tabus;
city *cityNode;
//edge edges[71];
ant ants[Number+1];
double density_new[Number+1][Number+1]; //每一只蚂蚁的信息素更新,density_new[0][]0不用.
//仅用上三角矩阵,即i(行)<=j(列)
double Lens_circle[Number+1]; //记录本次迭代中每一只蚂蚁所走的回路的长度
int Max_circle; //最大的迭代次数
int Now_circle; //当前迭代次数
int OptimizeLink[Number+1]; //路径最短的链表
double Min_path; //最优路径的长度
int ThisLink[Number+1]; //本次的最短路径
double This_path;
double Max_ThisPath;
double circle_path[Number+1]; //一次迭代每只蚂蚁的路径长度
//所有数组,仅用上三角矩阵,即i(行)<=j(列)
double edge_len[Number+1][Number+1]; //与*edges的长度相对应
double edge_info[Number+1][Number+1]; //可视信息,edge_len的倒数
double edge_den[Number+1][Number+1]; //与*edges的信息素浓度对应
double edge_choice[Number+1][Number+1]; //公式中选择路经的概率的分子
double edge_probab[Number+1][Number+1]; //选择某路经的概率
void copy(int *opt,Tabu *l2); //将l2链表复制给l1链表
void loadFile(); //读取文件信息
void input_Maxcircle(int Num);
void Initialize(); //初始化蚂蚁系统
void set_ant(); //不用参数,开始时将蚂蚁数组的序号与他的数据成员ant_id对应
void set_edge(edge &e,int index1,int index2);
void edge_init(); //初始化每条边上的浓度和长度信息
double Len_circle(ant a1); //计算一只蚂蚁走一个回路的路经长度.
double Len_circle(int a[]);
void edge_DensityUpdate(); //每一次迭代后,对每一条边上的信息素浓度进行更新
void probability(ant &a1); //计算出第a1只蚂蚁的概率选择,并将下一城市加入到
//tabu链表中直道tabu链满~
void save_optimizeLink(); //保存一次迭带中的最有路径
bool Tabus_equal(); //依次迭代结束时判断所有(70)的链表是否都相等
//相等则返回1,不等则返回0
void process(); //过程
double P_random(); //返回一个0到1的小数
};
double ant::ComputeLength(AntSystem *as)
{
int k,m;
double Lk=0;
TabuNode *p;
p=antsTabu.firstnode;
if ( antsTabu.firstnode == antsTabu.lastnode )
{
return 10E+04;
};
for (int i=1;i++<Number && p!=antsTabu.lastnode;p=p->next) //先除去尾和头节点的边长
{
if (p->data<=p->next->data) //保证i<=j,用上三角矩阵
Lk+=as->edge_len[p->data][p->next->data];
else
Lk+=as->edge_len[p->next->data][p->data];
}
k = antsTabu.firstnode->data;
m = antsTabu.lastnode->data;
if (k<=m)
{
Lk+=as->edge_len[k][m];
}
else
{
Lk+=as->edge_len[m][k];
}
return Lk;
}
//***********************************************************************
void city::set_city(int id,double x,double y)
{
city_x=x;
city_y=y;
city_index=id;
}
//***********************************************************************
// Tabu
Tabu::Tabu()
{
firstnode=lastnode=0;
// lastnode->next=0;
}
Tabu::~Tabu()
{
/* if (firstnode!=lastnode)
{
lastnode=firstnode;
delete lastnode;
}
*/
free();
}
int Tabu::queue_length(Tabu l1)
{
int length=0;
TabuNode *q;
q=l1.firstnode;
if (l1.lastnode==l1.firstnode)
{
// if (l1.lastnode->data==0)
// length=0;
// else
length=1;
}
else
//length=sizeof((l1.lastnode-l1.firstnode)/int+1);
{
while (q!=l1.lastnode)
{
q=q->next;
length++;
}
length++;
}
return length;
}
int Tabu::Insert(int &id)
{
if (!Inqueue( id)) //如果不在链表中,则插入
{
//TabuNode *newnode=(TabuNode *)malloc(sizeof(TabuNode));
TabuNode *newnode = new TabuNode;
newnode->data=id; //此两行定义是否正确?
newnode->next=0;
if (lastnode==firstnode &&firstnode==0)
firstnode=lastnode=newnode;
else
{
lastnode->next=newnode;
lastnode=newnode;
}
return 1;
}
else
return 0;
}
void Tabu::free()
{
// lastnode=firstnode=0;
// delete [] lastnode;
TabuNode *p=firstnode,*q;
// int n=69;
while(p!=0)
{q=p;p=p->next;delete q;};
firstnode=0;
lastnode=0;
}
bool Tabu::Inqueue(int id) //1表示在链表中,0表示不再链表中
{
TabuNode *checknode;
if (lastnode==firstnode)return 0;
else
{
checknode=firstnode;
while (checknode!=lastnode)
{
if (checknode->data==id)
return 1;
else
checknode=checknode->next;
}
if (lastnode->data!=id)
return 0;
else
return 1;
}
}
bool Tabu::Isequal(Tabu l1,Tabu l2) //判断2条Tabu链是否相等,1表示相等,0表示不等
{
TabuNode *l1_nowNode,*l2_nowNode;
l1_nowNode=l1.firstnode;
l2_nowNode=l2.firstnode;
while(l1_nowNode->data==l2_nowNode->data)
{
l1_nowNode=l1_nowNode->next;
l2_nowNode=l2_nowNode->next;
}
if (l1_nowNode!=l1.lastnode || l2_nowNode!=l2.lastnode) //用一个应该就可以
return false;
if (l1.lastnode->data!=l2.lastnode->data)
return false;
return true;
}
void AntSystem::copy(int *opt,Tabu *l2) //将l2链表复制给l1链表
{
/* int i;
TabuNode *p,*q;
p=l2.firstnode;
q=l1.firstnode;
// l1.free();
// for (int i=1;i<=70;i++)
for (;p!=l2.lastnode;p=p->next)
{
if(p->next==NULL)
i=0;
q->data=p->data;
q=q->next;
//p=p->next;
}
*/
TabuNode *p;
p=l2->firstnode;
for (;p!=l2->lastnode;p=p->next)
{
*(++opt)=p->data;
}
*(++opt)=l2->lastnode->data;
}
void Tabu::print()
{
TabuNode *nownode;
nownode=firstnode;
for (int i=1;i<=Number;i++)
{
cout<<nownode->data<<" - ";
if (nownode==lastnode)break;
nownode=nownode->next;
// if (i%10==0)
// cout<<endl;
}
// for (int i=1;i<=70;i++)
}
//***********************************************************************************
void AntSystem::input_Maxcircle(int Num)
{Max_circle=Num;}
void AntSystem::set_ant()
{
for (int i=1;i<=Number;i++)
ants[i].ant_id=i;
}
void AntSystem::set_edge(edge &e,int index1,int index2)
{
e.edge_index1=index1;
e.edge_index2=index2;
e.edge_length=pow(pow(cityNode[index1].city_x-cityNode[index2].city_x,2)+pow(cityNode[index1].city_y-cityNode[index2].city_y,2),0.5);
}
void AntSystem::edge_init() //初始化每条边上的浓度和长度信息
{
for (int i=1;i<=Number;i++)
for (int j=1;j<=Number;j++) //j从i开始,保证了只用上三角矩阵
{ //修改从1开始/2005.3
//set_edge(edges[i],i,j);
edge_len[i][j]=pow(pow(cityNode[i].city_x-cityNode[j].city_x,2)+pow(cityNode[i].city_y-cityNode[j].city_y,2),0.5);
edge_info[i][j]=1/edge_len[i][j];
edge_den[i][j]=c; //浓度
}
}
/*void AntSystem::loadFile() //读取文件信息
{
//string a;
CString a="";
int id,i=1;
double x,y;
ifstream inTspfile("st70.tsp",ios::in);
if (!inTspfile)
{
cerr<<"File could not be opened/n";
exit(1);
}
inTspfile >> a;
while (a!="NODE_COORD_SECTION")
{inTspfile.ignore();}
cityNode=new city[70];
while(!inTspfile.eof())
{
inTspfile>>id>>x>>y;
cityNode[i++].set_city(id,x,y);
}
inTspfile.close();
}
*/
void AntSystem::loadFile() //读取文件信息
{
// CString a;
int id,i=1;
double x,y;
ifstream inTspfile("tsp30.tsp",ios::in);
/* while (inTspfile>>a)
{
if (a=="NODE_COORD_SECTION")break;
}
*/
if (!inTspfile)
{
cerr<<"File could not be opened/n";
exit(1);
}
cityNode=new city[Number+1];
while(i<=Number)
{
inTspfile>>id>>x>>y;
cityNode[i++].set_city(id,x,y);
}
inTspfile.close();
}
void AntSystem::Initialize()
{
Now_circle=0;
for (int i=0;i<=Number;i++)
for (int j=0;j<=Number;j++)
{density_new[i][j]=0;}
//初始的信息素浓度在边的初始化中已经给出
for (int m=0;m<=Number;m++) //每次迭代前将每次蚂蚁走的路径长度回零
Lens_circle[m]=0;
Min_path=500000; //开始给最短路径一个很大的值
This_path=500000;
Max_ThisPath=0;
for (int j=1;j<=Number;j++)
OptimizeLink[j]=j;
}
double AntSystem::Len_circle(int a[]) //计算最优路径的长度
{
double Lk=0;
for (int i=1;i<Number;i++)
Lk+=edge_len[a[i]][a[i+1]];
Lk+=edge_len[a[1]][a[Number]];
return Lk;
}
double AntSystem::Len_circle(ant a1) //计算一只蚂蚁走一个回路的路经长度.
{
int k,m;
double Lk=0;
TabuNode *p;
// TabuNode *nowNode,
// nowNode=a1.antsTabu.firstnode;
p=a1.antsTabu.firstnode;
if ( a1.antsTabu.firstnode == a1.antsTabu.lastnode )
{
return 10E+04;
};
for (int i=1;i++<Number && p!=a1.antsTabu.lastnode;p=p->next) //先除去尾和头节点的边长
{
if (p->data<=p->next->data) //保证i<=j,用上三角矩阵
Lk+=edge_len[p->data][p->next->data];
else
Lk+=edge_len[p->next->data][p->data];
}
//此时结束for循环时,nowNode指向最后一个节点
/*
if (a1.antsTabu.firstnode->data<=a1.antsTabu.lastnode->data)
{
Lk+=edge_len[a1.antsTabu.firstnode->data][a1.antsTabu.lastnode->data];
}
else
{
Lk+=edge_len[a1.antsTabu.lastnode->data][a1.antsTabu.firstnode->data];
}
p = NULL;
*/
k = a1.antsTabu.firstnode->data;
m = a1.antsTabu.lastnode->data;
if (k<=m)
{
Lk+=edge_len[k][m];
}
else
{
Lk+=edge_len[m][k];
}
return Lk;
}
void AntSystem::edge_DensityUpdate() //每一次迭代后,对每一条边上的信息素浓度进行更新
{
// double sum_densNew=0;
//在一次迭代中,第k只蚂蚁的信息素浓度的更新量为Q(常量)本次的所走的路经长度
TabuNode *nowNode;
for (int m=1;m<=Number;m++)
{
nowNode=ants[m].antsTabu.firstnode;
//Lens_circle[m]=Len_circle(ants[m]);
Lens_circle[m]=ants[m].ComputeLength(this);
if (ants[m].antsTabu.firstnode!=ants[m].antsTabu.lastnode )
{
for (int n=1;n<=Number-1 && nowNode!=ants[m].antsTabu.lastnode;n++) //一只蚂蚁在它本次迭代所走的路经上产生的信息素更新
{ //未包含头尾节点
if (nowNode->data<=nowNode->next->data)
density_new[nowNode->data][nowNode->next->data]+=Q/Lens_circle[m];
else
density_new[nowNode->next->data][nowNode->data]+=Q/Lens_circle[m];
nowNode=nowNode->next;
}
if (ants[m].antsTabu.firstnode->data<=ants[m].antsTabu.lastnode->data)
density_new[ants[m].antsTabu.firstnode->data][ants[m].antsTabu.lastnode->data]+=Q/Lens_circle[m];
else
density_new[ants[m].antsTabu.lastnode->data][ants[m].antsTabu.firstnode->data]+=Q/Lens_circle[m];
};
}
for (int r=1;r<=Number;r++)
for (int s=r+1;s<=Number;s++)
edge_den[r][s]=info_remain*edge_den[r][s]+density_new[r][s];
//此时完成一次迭代后对每一条边的信息素更新
}
double AntSystem::P_random()
{
int32 seed = time(0);
TRandomMersenne rg(seed);
double a;
a=rg.Random();
return a;
}
void AntSystem::probability(ant &a1) //计算出第a1只蚂蚁的概率选择,并将下一城市加入到
{
short cnt=0; //tabu链表中直道tabu链满~
a1.antsTabu.Insert(a1.ant_id); //插入头节点
// srand(time(0)); //准备随机种子
double choice=0; //随机数。0~~10000
int antpos;
while (cnt++<Number) //概率选择下一个点插入tabu链,直到链满
{
// nowNode=a1.antsTabu.firstnode;
antpos=a1.antsTabu.lastnode->data;
for (int m=1;m<=Number;m++) //初始化为零,后面要用非零值
for (int n=1;n<=Number;n++)
{
edge_choice[m][n]=0;
edge_probab[m][n]=0;
}
double sum_info=0;
for (int i=1;i<=Number;i++)
{
if (i==antpos) continue;
if (!a1.antsTabu.Inqueue(i)) //表示城市i不在链表中
if (i<=antpos)
{
edge_choice[i][antpos]=pow(edge_den[i][antpos],a_para)*pow(edge_info[i][antpos],b_para);
sum_info+=edge_choice[i][antpos];
}
else
{
edge_choice[antpos][i]=pow(edge_den[antpos][i],a_para)*pow(edge_info[antpos][i],b_para);
sum_info+=edge_choice[antpos][i];
}
}
for (int k=1;k<=Number;k++) //找出可行路经(通往未走过的城市)
{ //并算出每条可行路经通过的概率
if (edge_choice[k][antpos]==0 && edge_choice[antpos][k]==0)
continue;
if (k<=antpos)
edge_probab[k][antpos]=edge_choice[k][antpos]/sum_info;
else
edge_probab[antpos][k]=edge_choice[antpos][k]/sum_info;
}
choice=P_random(); //choice属于[0,1]
bool flag=true;
// TabuNode *p;
// p=a1.antsTabu.firstnode;
// int antpos;
// while (p!=a1.antsTabu.lastnode)
// {
// p=p->next;
// };
// antpos=a1.antsTabu.lastnode->data;
for (int s=1;s<=Number && flag /*&& !a1.antsTabu.Inqueue(s)*/;s++)
{
if (a1.antsTabu.Inqueue(s)) continue;
int p1,p2;
if (antpos>s)
{
p1=s;
p2=antpos;
}
else
{
p1=antpos;
p2=s;
}
choice=choice-edge_probab[p1][p2];
if (choice<=0)
{
//此时choice<=0,则依概率选择出了路径
a1.antsTabu.Insert(s);
flag=false; //跳出双重循环
};
};
}
}
void AntSystem::save_optimizeLink() //如果第i只蚂蚁所走的回路比当前最有路径的长度短,
{ //则保存当前路径长度和链表
for (int i=1;i<=Number;i++)
{
//double a=Len_circle(ants[i]);
double a=ants[i].ComputeLength(this);
circle_path[i]=ants[i].ComputeLength(this);
if (a<Min_path/* && Len_circle(ants[i])>0*/)
{
Min_path=a;
copy(OptimizeLink,&ants[i].antsTabu);
}
if (a<This_path)
{
This_path=a;
copy(ThisLink,&ants[i].antsTabu);
}
if (a>Max_ThisPath)
{
Max_ThisPath=a;
}
}
}
bool AntSystem::Tabus_equal()
{
for (int i=1;i<=Number;i++)
{
if (!tabus->Isequal(ants[1].antsTabu,ants[i].antsTabu))
return 0;
}
return 1;
}
void AntSystem::process()
{
cout<<"各参数为:"<<endl;
cout<<"Q="<<Q<<" a_para="<<a_para<<" b_para="<<b_para<<" c="<<c<<" info_remain="
<<info_remain<<endl;
//第一步: 初始化:迭代计数器NT=0;对于每一条边(i,j),设初始值τij(t)=c以及⊿τij=0;
//将m只蚂蚁放在表示n个城市的节点上。
loadFile(); //读取文件信息
Initialize();
Now_circle=0; //当前迭代次数
set_ant(); //n只蚂蚁依次放在n个城市的节点上
edge_init(); //初始化边的长度和浓度
//第二步:令tabu链表的索引s=1;将k=1到m(m只蚂蚁)的起始点位置放入各自的tabu链表中
//第三步:重复此过程直到链表满(将重复n-1次):
// s=s+1;
// 从k=1到m(对于m只蚂蚁),根据公式(4)给出的概率Pij(t)选择移动到城市j。
// 将城市j放入tabu表。
/* a_para=0.05*Now_circle;
b_para=2;
if (b_para>=0)
b_para=2-0.1*a_para;
else
b_para=0;
cout<<"a_para=0.05*Now_circle; b_para=2-0.1*a_para;"<<endl;
*/
do
{
// cout<<"第"<<Now_circle+1<<"次迭代"<<endl;
for (int i=1;i<=Number;i++)
probability(ants[i]);
//第四步: 从k=1到m(对于每一只蚂蚁)
// 将第k只蚂蚁从终结点(τij(n)),移动到起始点位置(τij(1));
// 计算距离L(k);并更新所发现的最短距离。
// 计算并更新每条边的信息素浓度。
save_optimizeLink(); //保存本次迭代的最短路径长度和链表
edge_DensityUpdate();
//第五步:NC=NC+1;对于每一条边(i,j),令⊿τij=0;
// if (Now_circle==20)
// b_para=0;
Now_circle++;
for (int j=1;j<=Number;j++)
for (int k=j;k<=Number;k++)
density_new[j][k]=0;
//第六步:如果(NC<NCmax)或者(没有达到停滞状态)
//则:清空所有tabu链表;返回到步骤2;
//否则:打印最短路径;停止。
// save_optimizeLink(); //保存本次迭代的最短路径长度和链表
if (Now_circle!=Max_circle)
{
for (int m=1;m<=Number;m++) //清空m只蚂蚁的tabu链表
ants[m].antsTabu.free();
//free(ants[m].antsTabu);
}
/* cout<<"前"<<Now_circle<<"次迭代的最短路径为:"<<Min_path<<endl;
//OptimizeLink.print();
for (i=1;i<=70;i++)
cout<<OptimizeLink[i]<<" - ";
cout<<endl<<"第"<<Now_circle<<"次迭代的最短路径为:"<<This_path<<endl;
for (j=1;j<=70;j++)
cout<<ThisLink[j]<<" - ";
cout<<endl<<"*************************************************"<<endl;
*/
// if (Now_circle%10==0)
// {
cout<<Now_circle<<"/t"<<Min_path<<'/t'<<This_path<<'/t'<<Max_ThisPath<<"/t"<<"/t";
for (int x=1;x<=Number;x++)
cout<<circle_path[x]<<"/t";
cout<<endl;
// }
This_path=500000;
Max_ThisPath=0;
}while(/*!Tabus_equal() || */Now_circle<Max_circle);
cout<<"最短路径为:"<<Min_path<<endl;
//OptimizeLink.print();
for (int i=1;i<=Number;i++)
cout<<OptimizeLink[i]<<" - ";
/* cout<<"最后一次的路径为:"<<endl; //判断是否收敛
copy(LastLink,&ants[70].antsTabu);
for (int j=1;j<=70;j++)
cout<<LastLink[j]<<" - ";
*/
}
师兄实现的蚂蚁算法的一个改进措施,在最近几天里我要透彻学习之,并提出我自己的看法--11.18