蚂蚁算法的一个改进

#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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值