蟻羣算法簡單實現

#include <iostream>
#include <cmath>
#include <time.h>
#include <algorithm> 

#include <string.h>
#include <stdio.h>

#include <ctime>



using namespace std;
  
//該程序是以蟻羣系統爲模型寫的蟻羣算法程序(強調:非螞蟻周模型),以三個著名的TSP問題爲測試對象  
//通過微調參數,都可以獲得較好的解  
  
/* 
//----------(1)問題一:Oliver 30 城市 TSP 問題 best_length = 423.7406; ------------------------ 
//該程序最好的結果是423.741,可運行多次獲得 
//城市節點數目 
#define N 30 
//城市座標 
double C[N][2]={ 
    {2,99},{4,50},{7,64},{13,40},{18,54},{18,40},{22,60},{24,42},{25,62},{25,38}, 
    {37,84},{41,94},{41,26},{44,35},{45,21},{54,67},{54,62},{58,35},{58,69},{62,32}, 
    {64,60},{68,58},{71,44},{71,71},{74,78},{82,7},{83,46},{83,69},{87,76},{91,38} 
}; 
//----------上面參數是固定的,下面的參數是可變的----------- 
//螞蟻數量 
#define M 30 
//最大循環次數NcMax 
int NcMax = 500; 
//信息啓發因子,期望啓發式因子,全局信息素揮發參數,局部信息素揮發參數, 狀態轉移公式中的q0 
double alpha = 2, beta = 3, rou = 0.1, alpha1 = 0.1,  qzero = 0.01; 
//-----------問題一結束------------------------------------------------------------------------ 
*/  
  
/* 
//----------(2)問題二:Elion50 城市 TSP 問題 best_length = 427.96; ---------------------------- 
//該程序最好的結果是428.468,可運行多次獲得 
//城市節點數目 
#define N 50 
//城市座標 
double C[N][2]={ 
    {5,64}, {5,25}, {5,6}, {7,38}, {8,52}, {10,17}, 
    {12,42}, {13,13}, {16,57}, {17,33}, {17,63}, 
    {20,26}, {21,47}, {21,10}, {25,32}, {25,55}, 
    {27,68}, {27,23}, {30,48}, {30,15}, {31,62}, 
    {31,32}, {32,22}, {32,39}, {36,16}, {37,69}, 
    {37,52}, {38,46}, {39,10}, {40,30}, {42,57}, 
    {42,41}, {43,67}, {45,35}, {46,10}, {48,28}, 
    {49,49}, {51,21}, {52,33}, {52,41}, {52,64}, 
    {56,37}, {57,58}, {58,27}, {58,48}, {59,15}, 
    {61,33}, {62,42}, {62,63}, {63,69} 
}; 
//----------上面參數是固定的,下面的參數是可變的----------- 
//螞蟻數量 
#define M 50 
//最大循環次數NcMax 
int NcMax = 1000; 
//信息啓發因子,期望啓發式因子,全局信息素揮發參數,局部信息素揮發參數, 狀態轉移公式中的q0 
double alpha = 2, beta = 4, rou = 0.1, alpha1 = 0.1,  qzero = 0.01; 
//-----------問題二結束------------------------------------------------------------------------ 
*/  
  
//----------(3)問題三:Elion75 城市 TSP 問題 best_length = 542.31;  
//該程序最好的結果是542.309,可運行多次獲得   
//城市節點數目  
#define N 6  
//城市座標  
//double C[N][2]={  
//{6,25}, {7,43}, {9,56}, {10,70}, {11,28},  
//{12,17}, {12,38}, {15,5}, {15,14}, {15,56},  
//{16,19}, {17,64}, {20,30}, {21,48}, {21,45},  
//{21,36}, {22,53}, {22,22}, {26,29}, {26,13},  
//{26,59}, {27,24}, {29,39}, {30,50}, {30,20},  
//{30,60}, {31,76}, {33,34}, {33,44}, {35,51},  
//{35,16}, {35,60}, {36,6}, {36,26}, {38,33},  
//{40,37}, {40,66}, {40,60}, {40,20}, {41,46},  
//{43,26}, {44,13}, {45,42}, {45,35}, {47,66},  
//{48,21}, {50,30}, {50,40}, {50,50}, {50,70},  
//{50,4}, {50,15}, {51,42}, {52,26}, {54,38},  
//{54,10}, {55,34}, {55,45}, {55,50}, {55,65},  
//{55,57}, {55,20}, {57,72}, {59,5}, {60,15},  
//{62,57}, {62,48}, {62,35}, {62,24}, {64,4},  
//{65,27}, {66,14}, {66,8}, {67,41}, {70,64}  
//}; 



 
//----------上面參數是固定的,下面的參數是可變的-----------  
//螞蟻數量  
#define M 75  
//最大循環次數NcMax  
int NcMax =10;  
//信息啓發因子,期望啓發式因子,全局信息素揮發參數,局部信息素揮發參數, 狀態轉移公式中的q0  
double alpha = 2, beta = 5, rou = 0.1, alpha1 = 0.1,  qzero = 0.1;  
//-----------問題三結束------------------------------------------------------------------------  
  
  
//===========================================================================================================  
//局部更新時候使用的的常量,它是由最近鄰方法得到的一個長度  
//什麼是最近鄰方法?:)就是從源節點出發,每次選擇一個距離最短的點來遍歷所有的節點得到的路徑  
//每個節點都可能作爲源節點來遍歷  
double Lnn;  
//矩陣表示兩兩城市之間的距離  
double allDistance[N][N];  

  
//計算兩個城市之間的距離  
//double calculateDistance(int i, int j)  
//{  
//    return sqrt(pow((C[i][0]-C[j][0]),2.0) + pow((C[i][1]-C[j][1]),2.0));  
//}  
//  
////由矩陣表示兩兩城市之間的距離  
//void calculateAllDistance()  
//{  
//    for(int i = 0; i < N; i++)  
//    {  
//        for(int j = 0; j < N; j++)  
//        {  
//            if (i != j)  
//            {  
//                allDistance[i][j] = calculateDistance(i, j);  
//                allDistance[j][i] = allDistance[i][j];  
//            }  
//        }  
//    }  
//}  
  
//獲得經過n個城市的路徑長度  
double calculateSumOfDistance(int* tour)  
{  
    double sum = 0;  
    for(int i = 0; i< N ;i++)  
    {  
        int row = *(tour + 2 * i);  
        int col = *(tour + 2* i + 1);  
        sum += allDistance[row][col];  
    }  
    return sum;  
}  
  
class ACSAnt;  
  
class AntColonySystem  
{  
private:      
    double info[N][N], visible[N][N];//節點之間的信息素強度,節點之間的能見度  
public:   
    AntColonySystem()  
    {  
    }  
    //計算當前節點到下一節點轉移的概率  
    double Transition(int i, int j);      
    //局部更新規則  
    void UpdateLocalPathRule(int i, int j);   
    //初始化  
    void InitParameter(double value);     
    //全局信息素更新  
    void UpdateGlobalPathRule(int* bestTour, int globalBestLength);  
};  
  
//計算當前節點到下一節點轉移的概率  
double AntColonySystem::Transition(int i, int j)  
{  
    if (i != j)  
    {  
        return (pow(info[i][j],alpha) * pow(visible[i][j], beta));  
    }  
    else  
    {  
        return 0.0;  
    }     
}  
//局部更新規則  
void AntColonySystem::UpdateLocalPathRule(int i, int j)  
{  
    info[i][j] = (1.0 - alpha1) * info[i][j] + alpha1 * (1.0 / (N * Lnn));  
    info[j][i] = info[i][j];  
}  
//初始化  
void AntColonySystem::InitParameter(double value)  
{  
    //初始化路徑上的信息素強度tao0  
    for(int i = 0; i < N; i++)  
    {  
        for(int j = 0; j < N; j++)  
        {                 
            info[i][j] = value;  
            info[j][i] = value;  
            if (i != j)  
            {  
                visible[i][j] = 1.0 / allDistance[i][j];  
                visible[j][i] = visible[i][j];  
            }  
        }  
    }     
}  
  
//全局信息素更新  
void AntColonySystem::UpdateGlobalPathRule(int* bestTour, int globalBestLength)  
{  
    for(int i = 0; i < N; i++)  
    {  
        int row = *(bestTour + 2 * i);  
        int col = *(bestTour + 2* i + 1);  
        info[row][col] = (1.0 - rou) * info[row][col] + rou * (1.0 / globalBestLength);  
        info[col][row] =info[row][col];  
    }  
}  
  
class ACSAnt  
{  
private:  
    AntColonySystem* antColony;  
protected:  
    int startCity, cururentCity;//初始城市編號,當前城市編號  
    int allowed[N];//禁忌表      
    int Tour[N][2];//當前路徑  
    int currentTourIndex;//當前路徑索引,從0開始,存儲螞蟻經過城市的編號  
public:   
    ACSAnt(AntColonySystem* acs, int start)  
    {  
        antColony = acs;   
        startCity = start;  
    }     
    //開始搜索  
    int* Search();  
    //選擇下一節點  
    int Choose();  
    //移動到下一節點  
    void MoveToNextCity(int nextCity);  
  
};  
  
//開始搜索  
int* ACSAnt::Search()  
{  
    cururentCity = startCity;  
    int toCity;  
    currentTourIndex = 0;  
    for(int i  = 0; i < N; i++)  
    {  
        allowed[i] = 1;  
    }  
    allowed[cururentCity] = 0;  
    int endCity;  
    int count = 0;  
    do  
    {  
        count++;  
        endCity = cururentCity;  
        toCity = Choose();        
        if (toCity >= 0)  
        {             
            MoveToNextCity(toCity);  
            antColony->UpdateLocalPathRule(endCity, toCity);  
            cururentCity = toCity;  
        }         
    }while(toCity >= 0);  
    MoveToNextCity(startCity);  
    antColony->UpdateLocalPathRule(endCity, startCity);  
  
    return *Tour;  
}  
  
//選擇下一節點  
int ACSAnt::Choose()  
{  
    int nextCity = -1;        
    double q = rand()/(double)RAND_MAX;  
    //如果 q <= q0,按先驗知識,否則則按概率轉移,  
    if (q <= qzero)  
    {  
        double probability = -1.0;//轉移到下一節點的概率  
        for(int i = 0; i < N; i++)  
        {  
            //去掉禁忌表中已走過的節點,從剩下節點中選擇最大概率的可行節點  
            if (1 == allowed[i])  
            {  
                double prob = antColony->Transition(cururentCity, i);  
                if (prob  > probability)  
                {  
                    nextCity = i;  
                    probability = prob;  
                }  
            }  
        }  
    }  
    else  
    {  
        //按概率轉移           
        double p = rand()/(double)RAND_MAX;//生成一個隨機數,用來判斷落在哪個區間段  
        double sum = 0.0;             
        double probability = 0.0;//概率的區間點,p 落在哪個區間段,則該點是轉移的方向  
        //計算概率公式的分母的值  
        for(int i = 0; i < N; i++)  
        {  
            if (1 == allowed[i])  
            {  
                sum += antColony->Transition(cururentCity, i);  
            }  
        }  
        for(int j = 0; j < N; j++)  
        {  
            if (1 == allowed[j] && sum > 0)  
            {  
                probability += antColony->Transition(cururentCity, j)/sum;  
                if (probability >= p || (p > 0.9999 && probability > 0.9999))  
                {  
                    nextCity = j;  
                    break;  
                }  
            }  
        }     
    }     
    return nextCity;  
}  
  
//移動到下一節點  
void ACSAnt::MoveToNextCity(int nextCity)  
{  
    allowed[nextCity]=0;  
    Tour[currentTourIndex][0] = cururentCity;  
    Tour[currentTourIndex][1] = nextCity;  
    currentTourIndex++;  
    cururentCity = nextCity;  
}  
  
//------------------------------------------  
//選擇下一個節點,配合下面的函數來計算的長度  
int ChooseNextNode(int currentNode, int visitedNode[])  
{  
    int nextNode = -1;        
    double shortDistance = 0.0;  
    for(int i = 0; i < N; i++)  
    {  
        //去掉已走過的節點,從剩下節點中選擇距離最近的節點  
        if (1 == visitedNode[i])  
        {             
            if (shortDistance == 0.0)  
            {  
                shortDistance = allDistance[currentNode][i];  
                nextNode = i;  
            }  
            if(shortDistance < allDistance[currentNode][i])  
            {  
                nextNode = i;  
            }  
        }  
    }  
    return nextNode;  
}  
  
//給一個節點由最近鄰距離方法計算長度  
double CalAdjacentDistance(int node)  
{  
    double sum = 0.0;  
    int visitedNode[N];  
    for(int j = 0; j < N; j++)  
    {  
        visitedNode[j] = 1;   
    }  
    visitedNode[node] = 0;  
    int currentNode = node;  
    int nextNode;  
    do  
    {  
        nextNode = ChooseNextNode(currentNode, visitedNode);  
        if (nextNode >= 0)  
        {  
            sum += allDistance[currentNode][nextNode];  
            currentNode= nextNode;  
            visitedNode[currentNode] = 0;  
        }         
    }while(nextNode >= 0);  
    sum += allDistance[currentNode][node];  
    return sum;  
}  
  
//---------------------------------結束---------------------------------------------  
  
//--------------------------主函數--------------------------------------------------  
int main()  
{  

    for(int i=0;i<N;i++)
    {
    	for(int j=0;j<N;j++)
    	{
    		allDistance[i][j] = 100;
    	}
    }
    
//    allDistance[0][2] = allDistance[2][0] = 2;
//    allDistance[1][2] = allDistance[2][1] =1;
//    allDistance[1][3] = allDistance[3][1] =3;
//    allDistance[2][3] = allDistance[3][2] =5;
//    allDistance[3][4] = allDistance[4][3] =1;
//    allDistance[4][5] = allDistance[5][4] =1;

    allDistance[0][2]  = 2;
    allDistance[2][1] =1;
    allDistance[1][3]  =3;
    allDistance[2][3]  =5;
    allDistance[3][4]  =1;
    allDistance[4][5]  =1;


    time_t timer,timerl;  
  
    time(&timer);  
    unsigned long seed = timer;  
    seed %= 56000;  
    srand((unsigned int)seed);  
  
    //由矩陣表示兩兩城市之間的距離  
    //calculateAllDistance();  
    //蟻羣系統對象  
    AntColonySystem* acs = new AntColonySystem();  
    ACSAnt* ants[M];  
    //螞蟻均勻分佈在城市上  
    for(int k = 0; k < M; k++)  
    {  
        //ants[k] = new ACSAnt(acs, (int)(k%N));  
        ants[k] = new ACSAnt(acs, 3);  
    }  
    //calculateAllDistance();  
    //隨機選擇一個節點計算由最近鄰方法得到的一個長度  
    int node = rand() % N; 
	cout<<"node = "<<node<<endl; 
    //int node = 0;
    Lnn = CalAdjacentDistance(node);  
      
    //各條路徑上初始化的信息素強度  
    double initInfo = 1 / (N * Lnn);  
    acs->InitParameter(initInfo);      
      
    //全局最優路徑  
    int globalTour[N][2];  
    //全局最優長度  
    double globalBestLength = 0.0;    
    for(int i = 0; i < NcMax; i++)  
    {  
        //局部最優路徑  
        int localTour[N][2];  
        //局部最優長度  
        double localBestLength = 0.0;  
        //當前路徑長度  
        double tourLength;  
        for(int j = 0; j < M; j++)  
        {  
            int* tourPath = ants[j]->Search();  
            tourLength = calculateSumOfDistance(tourPath);                
            //局部比較,並記錄路徑和長度  
            if(tourLength < localBestLength || abs(localBestLength - 0.0) < 0.000001)  
            {                 
                for(int m = 0; m< N; m++)  
                {  
                    int row = *(tourPath + 2 * m);  
                    int col = *(tourPath + 2* m + 1);  
                    localTour[m][0] = row;  
                    localTour[m][1] = col;  
                }  
                localBestLength = tourLength;             
            }  
        }  
        //全局比較,並記錄路徑和長度  
        if(localBestLength < globalBestLength || abs(globalBestLength - 0.0) < 0.000001)  
        {                 
            for(int m = 0; m< N; m++)  
            {  
                globalTour[m][0] = localTour[m][0];  
                globalTour[m][1] = localTour[m][1];  
            }  
            globalBestLength = localBestLength;   
        }  
        acs->UpdateGlobalPathRule(*globalTour, globalBestLength);  
        //輸出所有螞蟻循環一次後的迭代最優路徑  
        cout<<"第 "<<i + 1<<" 迭代最優路徑:"<<localBestLength<<"."<<endl;  
        for(int m = 0; m< N; m++)  
        {  
            cout<<localTour[m][0]<<".";  
        }  
        cout<<endl;         
    }     
    //輸出全局最優路徑  
    cout<<"全局最優路徑長度:"<<globalBestLength<<endl;      
    cout<<"全局最優路徑:";  
    for(int m = 0; m< N; m++)  
    {  
        cout<<globalTour[m][0]<<".";  
    }  
    cout<<endl;  
    time(&timerl);  
    int t = timerl - timer;  
    return 0;  
}  

發佈了147 篇原創文章 · 獲贊 84 · 訪問量 20萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章