#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;
}
蟻羣算法簡單實現
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.