1. 程式人生 > >蟻群演算法解決tsp問題

蟻群演算法解決tsp問題

控制蟻群演算法走向的關鍵是資訊素,資訊素類似遺傳演算法的適應性函式,類似退火演算法的評價函式,影響著其中一隻螞蟻的下一步的選擇。

螞蟻:類似遺傳演算法的染色體,就是一條解,在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;
 }





總結:蟻群演算法的關鍵在於資訊素,而影響資訊素的因素只有兩個:螞蟻選擇這條路徑的數量和時間的流逝(越往後,越是之前的資訊素影響就越弱)。

  同時注意雖然現實中螞蟻是同時去找食物,但是在蟻群演算法中螞蟻出發卻是有先後之分的,而所有的螞蟻走完就視為一次迭代。