传送门(所有的实验都使用python实现)
一、实验目的
理解并使用蚁群算法
二、实验内容
实现基于蚁群算法的旅行商路线寻找
三、实验环境
使用Python3.0 在 eclipse进行编辑
四、实验步骤
1、输入介绍:
城市总数目为30,每个城市的坐标以(x,y)表示,x,y的取值均为0~30的随机数。
2、初始群体设定:
随机产生n条长度为m的数组。n代表个体数目,m代表城市个数。在本次实验中设定n=10,m=30。且同一个体中的m个数互不相同,因为每个城市只经过一次。
3、信息素强度初始化:
根据使用贪心算法所得到的路径len,初始化每条边信息素含量为m/len;本次实验计算可得len=300,m=30,故初始化每条边信息素含量为0.1;
4、路线寻找:
每只蚂蚁随机选择一个出发点,根据下面公式计算下个点的概率,并采用轮盘赌方式决定。决定的过程中不断更新禁忌表。
5. 信息素更新:
当所有蚂蚁成功行走出路线后,采用下列公式对于每条边进行信息素更新。为使得信息素更新明显,设置信息素强度Q=10000,挥发率p=0.1;
6.终止条件
分别进行5,20,50,100次迭代后终止。
运行截图:
5次迭代总距离:193.52
20次迭代总距离:143.708
50次迭代总距离:150.60
100次迭代总距离:140.136
五、总结
信息素强度的设置会直接影响到算法的迭代次数与效率,若强度设置的过低就会导致挥发速度比蚂蚁更新速度还快,最后导致最优路线上的信息素丢失,失去最优解。若强度设置过高,会影响启发式信息的比重,找到的解并非较优解。经过多次实验,我设置信息素强度为1万。
与遗传算法比较,个人觉得蚁群算法的效率高于遗传算法,遗传算法中的随机因素太多,导致最优解的寻找比较久,蚁群算法对于路径的寻找虽然有轮盘赌的随机因素,但是信息素和启发式信息的影响有起到一定的纠正作用。
python源码
#coding:gbk
import random
import math
import matplotlib.pyplot as plt
global n,m,best,Q;
global br;
best = 10000; #best记录最优距离,初始化无限大
n=10;m=30; #n:样本个数 m:城市个数
road = [[0]*(m) for i in range(n)] #开辟n*m的数组记录每个只蚂蚁行走的路线
tau = [[0]*(m) for i in range(n)] #禁忌表
con = [[0]*(m) for i in range(m)] #记录信息素浓度
dis = [[0]*(m) for i in range(m)] #邻接矩阵记录两点间的距离
game = [0.0]*m; #轮盘赌的概率
value = [0.0]*n; #value数组记录每只蚂蚁的路线长度
way =[0]*m; #way数组记录最优解路线
class no: #该类表示每个点的坐标
def __init__(self,x,y):
self.x=x;
self.y=y;
p=[];
def draw(t): #该函数用于描绘路线图
x=[0]*(m+1);y=[0]*(m+1);
for i in range(m):
x[i] =p[t[i]].x;
y[i] =p[t[i]].y;
x[m] =p[t[0]].x;
y[m] =p[t[0]].y;
plt.plot(x,y,color='r',marker='*' );
plt.show();
def mycol(): #城市坐标输入
p.append(no( 8 , 20 ));
p.append(no( 28 , 6 )); p.append(no( 27 , 24 )); p.append(no( 25 , 20 )); p.append(no( 5 , 14 )); p.append(no( 18 , 4 )); p.append(no( 21 , 22 ));
p.append(no( 19 , 17 )); p.append(no( 28 , 22 )); p.append(no( 16 , 18 )); p.append(no( 28 , 28 )); p.append(no( 11 , 28 )); p.append(no( 29 , 28 ));
p.append(no( 15 , 22 )); p.append(no( 25 , 24 )); p.append(no( 9 , 22 )); p.append(no( 17 , 16 )); p.append(no( 12 , 16 )); p.append(no( 5 , 21 ));
p.append(no( 6 , 6 )); p.append(no( 12 , 21 )); p.append(no( 11 , 28 )); p.append(no( 20 , 22 )); p.append(no( 17 , 10 )); p.append(no( 18 , 6 ));
p.append(no( 18 , 9 )); p.append(no( 25 , 24 )); p.append(no( 24 , 11 )); p.append(no( 25 , 12 )); p.append(no( 0 , 28 ));
def get_dis(a,b): #返回a,b两城市的距离
return math.sqrt((p[a].x-p[b].x) *(p[a].x-p[b].x) +(p[a].y-p[b].y) *(p[a].y-p[b].y));
def get_value(t): #计算蚂蚁t的路线长度
ans = 0.0;
for i in range(1,m): #两点距离公式
ans += math.sqrt((p[t[i]].x-p[t[i-1]].x) *(p[t[i]].x-p[t[i-1]].x) +(p[t[i]].y-p[t[i-1]].y) *(p[t[i]].y-p[t[i-1]].y));
ans += math.sqrt((p[t[0]].x-p[t[m-1]].x) * (p[t[0]].x-p[t[m-1]].x) +(p[t[0]].y-p[t[m-1]].y) *(p[t[0]].y-p[t[m-1]].y));
return ans;
def init(): #初始化函数
for i in range(m):
for j in range(m):
con[i][j] = 0.1; #初始化所有信息素为0.03
dis[i][j]=get_dis(i,j);
def rws(): #轮盘赌函数
num = random.random();
r = 0.0;
for i in range(m):
r += game[i];
if(r >= num): return i;
return m-1;
def move(x,loc): #蚂蚁x从loc位置爬行到下一个点
tol=0.0
pk = [0.0]*m;
for i in range(m):
if(tau[x][i] != 1and dis[loc][i] !=0): #概率计算
pk[i] = con[loc][i]*(1/dis[loc][i])*(1/dis[loc][i]);
else:
pk[i]=0;
tol += pk[i];
if(tol == 0): #启发式信息的总和为0,br标记迭代结束
tol=1;br=0;
for i in range(m): #分配轮盘赌的概率
game[i] =pk[i]/tol;
return rws(); #返回轮盘赌的选择
def slove():
global best,br;
for i in range(n):
for j in range(m):
tau[i][j] = 0; #初始化禁忌表
for i in range(n):
num = random.randint(0,m-1); #随机选择出发地点
tau[i][num]=1; road[i][0] = num;
for k in range(m-1):
for i in range(n):
ob = move(i,road[i][k]); #向前移动一步
tau[i][ob]=1;road[i][k+1] = ob; #更新禁忌表
if(br == 0): #br=0说明迭代已经到达终点,函数结束
return;
for i in range(n): #计算每只蚂蚁路径长度
value[i]=get_value(road[i]);
if(value[i] < best): #更新记录最优解
best = value[i];
for j in range(m):
way[j]= road[i][j];
for i in range(m): #挥发过程,每次挥发0.1
for j in range(m):
con[i][j]*=0.9;
for i in range(n): #信息素更新
for j in range(m-1):
a=road[i][j]; b=road[i][j+1];
con[a][b] += Q/value[i]; #Q为信息素强度
for i in range(m-1):
a=road[i][m-1]; b=road[i][0];
con[a][b] += Q/value[i];
mycol(); #数据输入
init(); #数据初始化
Q=10000; #信息素强度设置
br = 1; #迭代开始标记
for i in range(100): #控制迭代次数
if(br == 0):
break;
slove();
print(round(best,3)); #打印最优解距离,保留三位小数
draw(way); #画图描绘路线
print(way); #打印路线,以序列表示