蚁群算法基本原理
蚁群优化(Ant Colony Optimization,ACO)是人们受蚂蚁觅食行为启发而提出的一种元启发式算法,已经成功地解决了大量组合优化问题。而蚂蚁搜索食物的过程中主要通过在路径中释放信息素来标示路径,蚂蚁间通过交换信息素来寻找到最优路径。
蚂蚁在运动过程中,根据各条路径上的信息量决定其转移方向。在搜索过程中,蚂蚁根据各条路径上的信息量及路径的启发信息来计算转移概率。表示在t时刻蚂蚁k由某点i到某点j的路径(i,j)的概率。
式中: 等式左边是蚂蚁可能选择路径(i,j)的概率,s为蚂蚁k 下一步允许的路径;τ为t 时刻路径(i,j)上信息素浓度; α为信息启发因子,表示轨迹的相对重要性,反映了蚂蚁在运动过程中所积累的信息在蚂蚁运动过程中所起的作用,其值越大,蚂蚁探索能力越强,越倾向于选择其他蚂蚁经过的路径,蚂蚁之间协作性越强; β为期望启发因子,表示能见度的相对重要性,反映了蚂蚁在运动过程中启发信息在蚂蚁选择路径中的受重视程度,其值越大,在蚂蚁的开发能力越强,且该路径转移概率越接近于贪心规则。
蚂蚁决策过程伪代码如下:
r=U(0,1);
for 每个可能的路径A do
利用上式计算概率PA;
if r=<PA then
选择路径A
break;
end;
end;
蚁群算法自提出后成功运用于解决TSP问题,即旅行商问题。其C++实现如下:
#include <iostream>
#include <math.h>
#include <time.h>
const double ALPHA=1.0; //启发因子,信息素的重要程度
const double BETA=2.0; //期望因子,城市间距离的重要程度
const double ROU=0.5; //信息素残留参数
const int N_ANT_COUNT=34; //蚂蚁数量
const int N_IT_COUNT=2000; //迭代次数
const int N_CITY_COUNT=51; //城市数量
const double DBQ=100.0; //总的信息素
const double DB_MAX=10e9; //一个标志数,10的9次方
double g_Trial[N_CITY_COUNT][N_CITY_COUNT]; //两两城市间信息素,就是环境信息素
double g_Distance[N_CITY_COUNT][N_CITY_COUNT]; //两两城市间距离数组
double x_Ary[N_CITY_COUNT]=
{
36,49,52,20,40,21,17,31,52,51,
42,31,5,12,36,52,27,17,13,57,
62,42,16,8,7,27,30,43,58,58,
37,38,46,61,62,63,32,45,59,5,
10,21,5,30,39,32,25,25,48,56,
30
};
double y_Ary[N_CITY_COUNT]=
{
50,49,64,26,30,47,63,62,33,21,
41,32,25,42,16,41,23,33,13,58,
42,57,57,52,38,68,48,67,48,27,
69,46,10,33,63,69,22,35,15,6,
17,10,64,15,10,39,32,55,28,37,
40
};
int rnd(int nLow,int nUpper)
{
return nLow+(nUpper-nLow)*rand()/(RAND_MAX+1.0);
}
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));
}
//定义蚂蚁类
class CAnt
{
public:
CAnt(void);
~CAnt(void);
public:
int m_nPath[N_CITY_COUNT]; //蚂蚁走的路径
double m_dbPathLength; //蚂蚁走过的路径长度
int m_nAllowedCity[N_CITY_COUNT]; //没去过的城市编号数组
int m_nCurCityNo; //当前所在城市编号
int m_nMovedCityCount; //已经去过的城市数量
public:
void Init(); //初始化
int ChooseNextCity(); //选择下一个城市
void Move(); //蚂蚁在城市间移动
void Search(); //搜索路径
void CalPathLength(); //计算蚂蚁完成搜索后走过的路径长度
};
//构造函数
CAnt::CAnt(void)
{
}
//析构函数
CAnt::~CAnt(void)
{
}
//初始化函数,蚂蚁搜索前调用
void CAnt::Init()
{
for (int i=0;i<N_CITY_COUNT;i++)
{
m_nAllowedCity[i]=1; //设置全部城市为没有去过
m_nPath[i]=0; //蚂蚁走的路径全部设置为0
}
m_dbPathLength=0.0;
m_nCurCityNo=rnd(0,N_CITY_COUNT);
m_nPath[0]=m_nCurCityNo;
m_nAllowedCity[m_nCurCityNo]=0;
m_nMovedCityCount=1;
}
int CAnt::ChooseNextCity()
{
int nSelectedCity=-1;
double dbTotal=0.0;
double prob[N_CITY_COUNT];
for (int i=0;i<N_CITY_COUNT;i++)
{
if (m_nAllowedCity[i] == 1)
{
prob[i]=pow(g_Trial[m_nCurCityNo][i],ALPHA)*pow(1.0/g_Distance[m_nCurCityNo][i],BETA);
dbTotal=dbTotal+prob[i];
}
else
{
prob[i]=0.0;
}
}
double dbTemp=0.0;
if (dbTotal > 0.0)
{
dbTemp=rnd(0.0,dbTotal);
for (int i=0;i<N_CITY_COUNT;i++)
{
if (m_nAllowedCity[i] == 1)
{
dbTemp=dbTemp-prob[i];
if (dbTemp < 0.0)
{
nSelectedCity=i;
break;
}
}
}
}
if (nSelectedCity == -1)
{
for (int i=0;i<N_CITY_COUNT;i++)
{
if (m_nAllowedCity[i] == 1)
{
nSelectedCity=i;
break;
}
}
}
return nSelectedCity;
}
void CAnt::Move()
{
int nCityNo=ChooseNextCity();
m_nPath[m_nMovedCityCount]=nCityNo;
m_nAllowedCity[nCityNo]=0;
m_nCurCityNo=nCityNo;
m_nMovedCityCount++;
}
void CAnt::Search()
{
Init();
while (m_nMovedCityCount < N_CITY_COUNT)
{
Move();
}
CalPathLength();
}
void CAnt::CalPathLength()
{
m_dbPathLength=0.0;
int m=0;
int n=0;
for (int i=1;i<N_CITY_COUNT;i++)
{
m=m_nPath[i];
n=m_nPath[i-1];
m_dbPathLength=m_dbPathLength+g_Distance[m][n];
}
n=m_nPath[0];
m_dbPathLength=m_dbPathLength+g_Distance[m][n];
}
//TSP类
class CTsp
{
public:
CTsp(void);
~CTsp(void);
public:
CAnt m_cAntAry[N_ANT_COUNT];
CAnt m_cBestAnt;
public:
void InitData();
void UpdateTrial();
void Search();
};
//构造函数
CTsp::CTsp(void)
{
}
CTsp::~CTsp(void)
{
}
void CTsp::InitData()
{
m_cBestAnt.m_dbPathLength=DB_MAX;
double dbTemp=0.0;
for (int i=0;i<N_CITY_COUNT;i++)
{
for (int j=0;j<N_CITY_COUNT;j++)
{
dbTemp=(x_Ary[i]-x_Ary[j])*(x_Ary[i]-x_Ary[j])+(y_Ary[i]-y_Ary[j])*(y_Ary[i]-y_Ary[j]);
dbTemp=pow(dbTemp,0.5);
g_Distance[i][j]=ROUND(dbTemp);
}
}
for (int i=0;i<N_CITY_COUNT;i++)
{
for (int j=0;j<N_CITY_COUNT;j++)
{
g_Trial[i][j]=1.0;
}
}
}
void CTsp::UpdateTrial()
{
double dbTempAry[N_CITY_COUNT][N_CITY_COUNT];
memset(dbTempAry,0,sizeof(dbTempAry));
int m=0;
int n=0;
for (int i=0;i<N_ANT_COUNT;i++)
{
for (int j=1;j<N_CITY_COUNT;j++)
{
m=m_cAntAry[i].m_nPath[j];
n=m_cAntAry[i].m_nPath[j-1];
dbTempAry[n][m]=dbTempAry[n][m]+DBQ/m_cAntAry[i].m_dbPathLength;
dbTempAry[m][n]=dbTempAry[n][m];
}
n=m_cAntAry[i].m_nPath[0];
dbTempAry[n][m]=dbTempAry[n][m]+DBQ/m_cAntAry[i].m_dbPathLength;
dbTempAry[m][n]=dbTempAry[n][m];
}
for (int i=0;i<N_CITY_COUNT;i++)
{
for (int j=0;j<N_CITY_COUNT;j++)
{
g_Trial[i][j]=g_Trial[i][j]*ROU+dbTempAry[i][j];
}
}
}
void CTsp::Search()
{
char cBuf[256];
for (int i=0;i<N_IT_COUNT;i++)
{
for (int j=0;j<N_ANT_COUNT;j++)
{
m_cAntAry[j].Search();
}
for (int j=0;j<N_ANT_COUNT;j++)
{
if (m_cAntAry[j].m_dbPathLength < m_cBestAnt.m_dbPathLength)
{
m_cBestAnt=m_cAntAry[j];
}
}
UpdateTrial();
sprintf(cBuf," [%d] %.0f",i+1,m_cBestAnt.m_dbPathLength);
if (i % 8 == 0)
{
printf("\n");
}
printf(cBuf);
}
}
int main()
{
//用当前时间点初始化随机种子,防止每次运行的结果都相同
time_t tm;
time(&tm);
unsigned int nSeed=(unsigned int)tm;
srand(nSeed);
//开始搜索
CTsp tsp;
tsp.InitData(); //初始化
tsp.Search();
//输出结果
printf("\nThe shortest distance is :%0.1f\n",tsp.m_cBestAnt.m_dbPathLength);
printf("\nThe best tour is :\n");
char cBuf[128];
for (int i=0;i<N_CITY_COUNT;i++)
{
if (i % 20 == 0)
{
printf("\n");
}
printf(cBuf);
}
return 0;
}
运行结果如下: