TSP_旅行商問題
阿新 • • 發佈:2018-12-26
#include <iostream> #include <fstream> #include <iomanip> // 本文用於輸出對齊 #include <stdlib.h> #include <ctime> #include <algorithm> #include "GA.h" using namespace std; int IndexCross_i; int IndexCross_j; int main(){ time_t T_begin = clock(); Graph G; CreateGraph(G); srand ( unsigned ( time(0) ) ); InitialGroup(G); TSP_Evolution(G); // 遺傳演算法 time_t T_end = clock(); double RunningTime = double(T_end - T_begin) / CLOCKS_PER_SEC; cout<<endl<<"【 程式執行時間 RunningTime = " << RunningTime << " 】"<<endl; system("pause"); return 0; } void CreateGraph(Graph &G){ ifstream read_in; read_in.open("L:\\Coding\\TSP_遺傳演算法\\TSP_遺傳演算法\\city_150.txt"); if (!read_in.is_open()) { cout<<"檔案讀取失敗."<<endl; return; } read_in >> G.vex_num; // read_in >> G.arc_num; G.arc_num = 0; for (int i = 0;i < G.vex_num; i++) { read_in >> G.vexs[i]; } G.vexs[G.vex_num] = '\0'; // char的結束符. for (int i = 0; i < G.vex_num;i++) { for (int j = 0; j < G.vex_num; j++) { read_in >> G.arcs[i][j]; // calculate the arc_num if (G.arcs[i][j] > 0) { G.arc_num++; } } } // display cout<<"無向圖建立完畢,相關資訊如下:"<<endl; cout<<"【頂點數】 G.vex_num = "<<G.vex_num<<endl; cout<<"【邊數】 G.arc_num = "<<G.arc_num<<endl; cout<<"【頂點向量】 vexs[max_vexNum] = "; for (int i = 0; i < G.vex_num; i++) { cout << G.vexs[i] << " "; } } void InitialGroup(Graph G){ cout<<"----------------------【遺傳演算法引數】-----------------------"<<endl; cout<<"【城市個數】 CITY_NUM ="<< CITY_NUM <<endl; cout<<"【群體規模】 GROUP_NUM = "<< GROUP_NUM <<endl; cout<<"【子代規模】 SON_NUM = "<< SON_NUM <<endl; cout<<"【變異概率】 P_INHERIATANCE = "<< P_INHERIATANCE <<endl; cout<<"【雜交概率】 P_COPULATION = "<< P_COPULATION <<endl; cout<<"【迭代次數】 ITERATION_NUM = "<< ITERATION_NUM <<endl; double total_length = 0.0; for(int i = 0;i < GROUP_NUM; i++){ for (int j = 0;j < G.vex_num; j++) { TSP_Groups[i].path[j] = G.vexs[j]; } random_shuffle(TSP_Groups[i].path + 1, TSP_Groups[i].path + G.vex_num); if (Check_path(G, TSP_Groups[i])) { TSP_Groups[i].length_path = CalculateLength(G, TSP_Groups[i]); total_length += TSP_Groups[i].length_path; }else{ cout<<"【error!城市路徑產生重複城市!】"<<endl; TSP_Groups[i].length_path = MAX_INT; TSP_Groups[i].P_Reproduction = 0; } } Calc_Probablity(G, total_length); TSP_Evaluate(G); } // 處理物件:每次新產生的群體, 計算每個個體的概率 // 問題:解決TSP問題, 路徑越短概率應該越高 // 方案:對於當前總群, 將所有個體路徑取倒數, 然後乘以該總群的總路徑得到大於1的值, 然後進行歸一化, 取得概率 // 歸一化:累加當前所有大於1的個體的偽概率, 得到TempTotal_P, 每個概率再分別除以 TempTotal_P 進行歸一化 void Calc_Probablity(Graph G, double total_length){ double TempTotal_P = 0.0; for (int i = 0; i < GROUP_NUM ;i++) { TSP_Groups[i].P_Reproduction = (1.0 / TSP_Groups[i].length_path ) * total_length; TempTotal_P += TSP_Groups[i].P_Reproduction; } for (int i = 0;i < GROUP_NUM; i++) { TSP_Groups[i].P_Reproduction = TSP_Groups[i].P_Reproduction / TempTotal_P; } } void TSP_Evolution(Graph G){ /* */ int iter = 0; while(iter < ITERATION_NUM){ // cout<<"***********************【第次"<<(iter + 1)<<"迭代】*************************"<<endl; // 1. 選擇 int Father_index = Evo_Select(G); int Mother_index = Evo_Select(G); while (Mother_index == Father_index) { // 防止Father和Mother都是同一個個體 -> 自交( 父母為同一個個體時, 母親重新選擇, 直到父母為不同的個體為止 ) // cout<<"Warning!【Father_index = Mother_index】"<<endl; Mother_index = Evo_Select(G); } // TSP_Groups[]為當前總群 TSP_solution Father = TSP_Groups[Father_index]; TSP_solution Mother = TSP_Groups[Mother_index]; // 2. 交叉, 儲存在全域性變臉 Son_solution[] 陣列 - 通過M次雜交, 產生2M個新個體, 2M >= GROUP_NUM int M = GROUP_NUM - GROUP_NUM/2; Length_SonSoliton = 0; // 遺傳產生的個體個數, 置零重新累加 while(M){ double Is_COPULATION = ((rand()%100 + 0.0) / 100); if (Is_COPULATION > P_COPULATION) { // cout<<"[ 這兩個染色體不進行雜交 ]Is_COPULATION = "<<Is_COPULATION<<endl; }else{ // 雜交, 將結果儲存於遺傳個體總群,全域性變數Son_solution[] Evo_Cross(G, Father, Mother); M--; } } // 3. 變異:針對 Son_solution[] double total_length = 0.0; // 更新新個體的概率 for (int IndexVariation = 0;IndexVariation < Length_SonSoliton; IndexVariation++) { double RateVariation = float(rand()%100) / 100; // 產生的隨機數小於變異概率 則該個體進行變異 if (RateVariation < P_INHERIATANCE) { Evo_Variation(G, IndexVariation); } // 經過變異處理後 重新計算路徑值 if (!Check_path(G, Son_solution[IndexVariation])) { cout<<"【Error! 路徑有重複!】"<<endl; } // 產生新個體, 計算新路徑和新概率 Son_solution[IndexVariation].length_path = CalculateLength(G, Son_solution[IndexVariation]); total_length += Son_solution[IndexVariation].length_path; } Calc_Probablity(G, total_length); /* cout<<"【遺傳產生的子代個體如下...】"<<endl; for (int i = 0; i < Length_SonSoliton; i++) { for (int j = 0;j < G.vex_num;j++) { cout<<Son_solution[i].path[j]<<" -> "; } cout<<Son_solution[i].path[0]<<" length_path = "<<Son_solution[i].length_path<<" P_Reproduction = "<<Son_solution[i].P_Reproduction<<endl; } */ // 4. 更新群體 // 參與物件:父代 + 遺傳的子代 Evo_UpdateGroup(G); iter++; } } // 選擇 /* 輸入:當前總群 輸出:按照一個評價, 隨機從當前總群篩選出雜交物件, 本程式每次返回一個個體 選擇方案:比例選擇規則, [輪盤賭選擇] 機制:反映在對父代種群中每一個體所賦予的允許繁殖概率及其從2M箇中間個體中如何選擇子代種群的機制上! */ /* [輪盤賭選擇] - 輪盤賭選擇是從染色體群體中選擇一些成員的方法,被選中的機率和它們的適應性分數成比例,染色體的適應性分數愈高,被選中的概率也愈多. 1. 隨機產生一個概率 selection_P 2. [概率分佈函式]宣告變數 distribution_P = 0, 對於每個個體, 依次累加個體的概率到distribution_P上, 判斷當前隨機概率selection_P是否小於distribution_P, 若是則中該染色體, 結束迴圈 */ int Evo_Select(Graph G){ double selection_P = ((rand()%100 + 0.0) / 100); // cout<<"selection_P = "<<selection_P<<endl; double distribution_P = 0.0; for (int i = 0; i < GROUP_NUM; i++) { distribution_P += TSP_Groups[i].P_Reproduction; if (selection_P < distribution_P) { return i; } } cout<<"【ERROR!】Evo_Select() 輪盤賭選擇有誤..."<<endl; return 0; } // 交叉 /* 輸入:[TSP_Father , TSP_Mother]兩個個體作為父母, 進行雜交 輸出:通過雜交產生新個體(遺傳演算法產生2個新個體, 演化演算法產生1個新個體) 雜交方案:[父子混合選擇][自然選擇 - 父母不參與競爭] -- [演化策略]所使用的雜交運算元是從兩個個體生成一個個體的操作 -- [遺傳演算法]生成兩個新個體。常見的“中間雜交”(intermediate crossover)及“隨機雜交”(random crossover)等! */ /* TSP_雜交具體方法: 1. 隨機選取兩個交叉點i和j,記為 Father_Cross 和 Mother_Cross 2. 將兩交叉點中間的基因段互換 3. 分別對Father和Mother的路徑進行衝突處理: -- 以Father為例, 保持Father_Cross基因段不變, 基因段以外的部分與Father_Cross基因段衝突的城市, 用Father_Cross和Mother_Cross對應的位置去互換, 直到沒有衝突. -- 衝突城市的確定: Father_Cross 和 Mother_Cross去補集,存放於陣列 Conflict[] 中. */ void Evo_Cross(Graph G, TSP_solution TSP_Father, TSP_solution TSP_Mother){ // 雜交過程:隨機產生雜交的位置, 保證 IndexCross_i < IndexCross_j【全域性變數】 IndexCross_i = rand() % (CITY_NUM - 1) + 1; // 不能取到起始城市 IndexCross_j = rand() % (CITY_NUM - 1) + 1; // if (IndexCross_i > IndexCross_j) { int temp = IndexCross_i; IndexCross_i = IndexCross_j; IndexCross_j = temp; } if (IndexCross_j == CITY_NUM || IndexCross_i == 0) { cout<<"[ 雜交過程的隨機數產生有問題... ]"<<endl; } // 雜交基因段 int Father_Cross[CITY_NUM]; // 父親遺傳基因段 int Mother_Cross[CITY_NUM]; // 母親遺傳基因段 int Length_Cross = 0; // 雜交的個數 for (int i = IndexCross_i;i <= IndexCross_j; i++) { Father_Cross[Length_Cross] = TSP_Father.path[i]; Mother_Cross[Length_Cross] = TSP_Mother.path[i]; Length_Cross++; } // 開始雜交 - 處理 TSP_Father:找到Father_Cross[]中會產生衝突的城市 int *Conflict_Father; // 儲存衝突的位置 int *Conflict_Mother; int Length_Conflict = 0; // 衝突的個數 Conflict_Father = Get_Conflict(Father_Cross, Mother_Cross, Length_Cross, Length_Conflict); Conflict_Mother = Get_Conflict(Mother_Cross, Father_Cross, Length_Cross, Length_Conflict); // Father and Mother 交換基因段 int city_temp; for (int i = IndexCross_i; i <= IndexCross_j; i++) { city_temp = TSP_Father.path[i]; TSP_Father.path[i] = TSP_Mother.path[i]; TSP_Mother.path[i] = city_temp; } // 開始雜交 - 處理 TSP_Mother, 其中Length_Conflict會在函式Get_Conflict()中改變並儲存 TSP_solution Descendant_ONE = Handle_Conflict(G, TSP_Father, Conflict_Father, Conflict_Mother, Length_Conflict); // 解決 TSP_Father 的衝突 TSP_solution Descendant_TWO = Handle_Conflict(G, TSP_Mother, Conflict_Mother, Conflict_Father, Length_Conflict); // 解決 TSP_Mother 的衝突 Son_solution[Length_SonSoliton++] = Descendant_ONE; Son_solution[Length_SonSoliton++] = Descendant_TWO; } TSP_solution Handle_Conflict(Graph G, TSP_solution ConflictSolution, int *Detection_Conflict, int *Model_Conflict, int Length_Conflict){ for (int i = 0; i <= Length_Conflict; i++) { bool flag_FindCity = false; int index = 0; // [0, IndexCross_i) 尋找衝突 for (index = 0; index < IndexCross_i; index++) { if (Model_Conflict[i] == ConflictSolution.path[index]) { flag_FindCity = true; break; } } // 第一段沒找到, 找剩餘的部分【除了交換的基因段外】 if (!flag_FindCity) { // [IndexCross_i + 1, G.vex_num) 尋找衝突 for (index = IndexCross_j + 1; index < G.vex_num; index++) { if (Model_Conflict[i] == ConflictSolution.path[index]) { break; } } } // 9 8 [1 4 0 3 2] 3 2 0 --> ConflictSolution // 8 7 [4 5 6 7 1] 9 6 5 // [0 3 2] --> Detection_Conflict // [4 5 6] --> Model_Conflict // 解決衝突, index 為當前i衝突的位置, 用Model_Conflict去替換. // cout<<"index = "<<index<<endl; ConflictSolution.path[index] = Detection_Conflict[i]; } /* cout<<endl<<"【解決衝突】基因組為:"; for (int i = 0;i < G.vex_num;i++) { cout<<ConflictSolution.path[i]<<" -> "; } cout<<ConflictSolution.path[0]<<endl; // 重新計算新路徑的長度 // CalculateLength(G, ConflictSolution); */ if (!Check_path(G, ConflictSolution)) { cout<<"【error - 衝突未解決......】"<<endl; } // cout<<" length_path = "<<ConflictSolution.length_path<<" P_Reproduction = "<<ConflictSolution.P_Reproduction<<endl; return ConflictSolution; } int *Get_Conflict(int Detection_Cross[], int Model_Cross[], int Length_Cross, int &Length_Conflict){ // 同時存在於 Father_Cross 和 Mother_Cross 為不衝突的城市, 反之是衝突的城市. // Detection_Cross[]:表示當前搜尋的個體, 即找衝突的物件 // Model_Cross[]: // int Conflict[CITY_NUM]; int *Conflict = new int[CITY_NUM]; Length_Conflict = 0; for (int i = 0; i < Length_Cross; i++) { bool flag_Conflict = true; // 判斷是否屬於衝突 for (int j = 0; j < Length_Cross; j++) { if (Detection_Cross[i] == Model_Cross[j]) { // 結束第二層迴圈 j = Length_Cross; flag_Conflict = false; // 該城市不屬於衝突 } } if (flag_Conflict) { Conflict[Length_Conflict] = Detection_Cross[i]; Length_Conflict++; } } return Conflict; } // 變異 /* 輸入:雜交得到的所有個體(大於總群規模) 輸出:通過變異策略, 以一定的變異概率(確定變異個數)隨機選擇個體進行變異 變異策略:隨機交換染色體的片段, TSP - 隨機交換兩個城市的位置 */ void Evo_Variation(Graph G, int Index_Variation){ // 隨機產生兩個隨機數表示兩個城市的位置, 並進行位置交換 int City_i = (rand() % (CITY_NUM - 1)) + 1; // [1, CITY_NUM - 1]起始城市不變異 int City_j = (rand() % (CITY_NUM - 1)) + 1; // while(City_i == City_j){ City_j = (rand() % (CITY_NUM - 1)) + 1; } // 交換城市位置 - 變異 int temp_City = Son_solution[Index_Variation].path[City_i]; Son_solution[Index_Variation].path[City_i] = Son_solution[Index_Variation].path[City_j]; Son_solution[Index_Variation].path[City_j] = temp_City; } // 父代 - TSP_Groups[] // 子代 - Son_solution[] void Evo_UpdateGroup(Graph G){ TSP_solution tempSolution; // 先對子代 - Son_solution[] 依據路徑長度進行排序 - 降序[按路徑從大到小] for (int i = 0; i < Length_SonSoliton; i++) { for (int j = Length_SonSoliton - 1; j > i; j--) { if ( Son_solution[i].length_path > Son_solution[j].length_path ) { tempSolution = Son_solution[i]; Son_solution[i] = Son_solution[j]; Son_solution[j] = tempSolution; } } } /* cout<<"【氣泡排序後...】"<<endl; for (int i = 0; i < Length_SonSoliton; i++) { cout<<"length_path = "<<Son_solution[i].length_path<<endl; } */ // 更新 for (int i = 0; i < Length_SonSoliton; i++) // 子代 - 按路徑從大到小排序 { for (int j = 0; j < GROUP_NUM; j++) // 父代 { if ( Son_solution[i].length_path < TSP_Groups[j].length_path ) { TSP_Groups[j] = Son_solution[i]; // 種群更新 break; } } } TSP_Evaluate(G); } double CalculateLength(Graph G, TSP_solution newSolution){ double _length = 0; for (int i = 0; i < G.vex_num - 1; i++) { int _startCity = newSolution.path[i] - 1; // 路徑下標是從 1 開始儲存 int _endCity = newSolution.path[i+1] - 1; if (G.arcs[_startCity][_endCity] == -1) { return MAX_INT; } else{ _length += G.arcs[_startCity][_endCity]; } } // 判斷該路徑是否能回到起始城市 if (G.arcs[newSolution.path[G.vex_num - 1]][newSolution.path[0] - 1] == -1) { return MAX_INT; } else{ _length += G.arcs[newSolution.path[G.vex_num - 1] - 1][newSolution.path[0] - 1]; // cout<<"_length = "<<_length<<endl; return _length; } } bool Check_path(Graph G, TSP_solution CurrentSolution){ for (int i = 0; i < G.vex_num;i++) { for (int j = i + 1; j < G.vex_num; j++) { if (CurrentSolution.path[i] == CurrentSolution.path[j]) { return false; } } } return true; } /* // TSP - 評價函式 // 輸入:當前總群 TSP_Groups[] - 包括 每個個體的路徑和所需的長度 // 輸出:當前總群中, 最優的個體:bestSolution // 評價方法:路徑最短的為最優 */ void TSP_Evaluate(Graph G){ TSP_solution bsetSolution; bsetSolution = TSP_Groups[0]; for (int i = 1; i < GROUP_NUM; i++) { if (bsetSolution.length_path > TSP_Groups[i].length_path) { bsetSolution = TSP_Groups[i]; } } cout<<"當前最優個體 bsetSolution = "; for (int i = 0;i < G.vex_num;i++) { cout<<bsetSolution.path[i]<<" -> "; } cout<<bsetSolution.path[0]<<" length = "<<bsetSolution.length_path<<endl; }