蟻群演算法解決tsp問題
阿新 • • 發佈:2019-01-11
控制蟻群演算法走向的關鍵是資訊素,資訊素類似遺傳演算法的適應性函式,類似退火演算法的評價函式,影響著其中一隻螞蟻的下一步的選擇。
螞蟻:類似遺傳演算法的染色體,就是一條解,在tsp問題中螞蟻的路徑就是tsp的解。
資訊素:評價函式,與路徑成反比
螞蟻數量:一次迭代有多少隻螞蟻在跑(注意不是一起跑,而是先後放上一隻螞蟻)
迭代次數T:所有螞蟻跑完視為一次迭代週期。
程式流程:
1,隨機生成距離矩陣
進入迴圈while(t<T)
{
2,資訊素遞減(只有較近的資訊素才能影響這一步)
3,對於每一隻螞蟻,隨機生成起點,標記起點為訪問過
進入迴圈(尋找城市數量-1次)(起點已經有了)
{
4,尋找周圍城市的最大資訊素
5,隨機生成0~1的數如果小於bugp(螞蟻正常選擇)則從最大資訊素城市中找一個作為下一個
否則(螞蟻犯錯誤了,有木有感覺像退火演算法裡的允許犯錯的那個函式)隨機生成一個未訪問過的點作為下一個(因為至少你要保證可行吧)
6,標記這個點被訪問過
}
修改資訊素,修改方式為原來資訊素+Q/這條路徑長度(Q為1個常數)
t++;
}
輸出最優解。
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> #define T 1000//最大迭代次數 #define n 1000//螞蟻數量 #define cities 10//城市數量 #define bugp 0.9//每一次選擇操作的出錯概率 #define alpha 0.1//每一次資訊素的消失速率 #define Q 1 int start; int biggest[cities],biggestsum;//儲存資訊素最多時所對應的點(畢竟資訊素最大值所對應的邊不止一條,biggest記錄下那些邊的對應的終點,biggestsum為biggest的元素個數) int distance[cities][cities];//城市的距離矩陣 double phe[cities][cities];//邊所對應的資訊素濃度(之所以選擇邊是因為點容易受到周圍優秀的點的影響) int ant;//螞蟻當前所在點 int bugsum,bugTry[cities];//出錯時可供選擇的城市數量和城市下標 int visit[cities];//用來標記城市是否已經經過 int path[n][cities+1];//記錄每一個螞蟻所走過的城市 void initdistance() { int i,j; memset(distance,0,sizeof(distance)); srand(time(NULL)); for (i=0;i<cities;i++) for (j=i+1;j<cities;j++) { distance[i][j]=rand()%100; distance[j][i]=distance[i][j]; } printf("城市的距離矩陣如下:\n"); for (i=0;i<cities;i++) { for (j=0;j<cities;j++) printf("%4d",distance[i][j]); printf("\n"); } } int main() { int i,j,k,p,t,n1,n2,r; double d; double max;//記錄下最大資訊素濃度 double sumdistance; initdistance();//初始化城市矩陣 t=0; for (i=0;i<cities;i++) for (j=0;j<cities;j++) phe[i][j]=1;//初始化每一條邊的資訊素濃度 srand(time(NULL)); for (i=0;i<n;i++) path[i][0]=rand()%cities;//每一個螞蟻隨機在起點 while(t<T) { for (i=0;i<cities;i++) for (j=0;j<cities;j++) phe[i][j]=phe[i][j]*alpha;//每一次資訊素逐漸消逝 for (i=0;i<n;i++)//對於每一隻螞蟻 { start=path[i][0];//記錄下起點 memset(visit,0,sizeof(visit));//清零標記陣列 visit[start]=1; ant=start; for (j=1;j<cities;j++)//選取剩下的cities-1個城市 { bugsum=biggestsum=max=0; for (p=0;p<cities;p++) if (!visit[p]) max=max>phe[ant][p]?max:phe[ant][p];//尋找周圍最大的資訊素的那條邊(其實是為了找到那個p點) for (p=0;p<cities;p++) { if ((max==phe[ant][p])&&(!visit[p])) biggest[biggestsum++]=p;//記錄下資訊素濃度最大的點(注意一般不止一個點) } for (p=0;p<cities;p++) if (!visit[p]) bugTry[bugsum++]=p;//記錄下總共可供選擇的點 d=rand()%100; d=d/100; if (d<bugp)//如果螞蟻選擇正確 ant=biggest[rand()%biggestsum];//選擇資訊素最大的點 else//如果螞蟻選擇錯誤 ant=bugTry[rand()%bugsum];//只選擇成立的點(未必最優) visit[ant]=1; path[i][j]=ant; } } //上面是每一隻螞蟻的選擇,而一次全部選擇後,更新資訊素 for (i=0;i<n;i++) { sumdistance=0; for (j=1;j<cities;j++) { n1=path[i][j-1]; n2=path[i][j]; sumdistance=sumdistance+distance[n1][n2]; } n1=path[i][cities-1]; n2=path[i][0]; sumdistance=sumdistance+distance[n1][n2];//注意要回到起點 for (j=1;j<cities;j++) { n1=path[i][j-1]; n2=path[i][j]; phe[n1][n2]=phe[n1][n2]+Q/sumdistance;//更新資訊素,注意因為資訊素還要再次遞減,所以就好比2進位制的權,越靠近話語權越重 } n1=path[i][cities-1]; n2=path[i][0]; phe[n1][n2]=phe[n1][n2]+Q/sumdistance; } t++;//這樣迭代次數+1 } max=999999; for (i=0;i<n;i++) { sumdistance=0; for (j=1;j<cities;j++) { n1=path[i][j-1]; n2=path[i][j]; sumdistance=sumdistance+distance[n1][n2]; } n1=path[i][cities-1]; n2=path[i][0]; sumdistance=sumdistance+distance[n1][n2]; if (sumdistance<max) { max=sumdistance; r=i; } } printf("最短路徑為:%.4f\n",max); printf("路徑為:\n"); for (i=0;i<cities;i++) printf("%d ",path[r][i]);//第r個螞蟻是最優的 printf("%d\n",path[r][0]); return 0; }
總結:蟻群演算法的關鍵在於資訊素,而影響資訊素的因素只有兩個:螞蟻選擇這條路徑的數量和時間的流逝(越往後,越是之前的資訊素影響就越弱)。
同時注意雖然現實中螞蟻是同時去找食物,但是在蟻群演算法中螞蟻出發卻是有先後之分的,而所有的螞蟻走完就視為一次迭代。