1. 程式人生 > >TSP_旅行商問題

TSP_旅行商問題

#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;

}