TSP問題(換位表達,啟發式交叉,啟發式變異)C++實現
旅行商問題
一 染色體表達方式
染色體的表達方式採用換位表達,它是TSP巡迴的最自然的表達,如下圖:
它的訪問順序為 3-2-5-4-7-1-6-9-8,染色體中基因的值表示城市,基因的順序表示訪問城市的順序,這種表達的搜尋空間是澄海市順序“換位”的集合,採用傳統的單點交叉時,可能導致非法的巡迴。
二 染色體交叉
本課題中的染色體交叉使用的是啟發式交叉,啟發式交叉的步驟如下(最近鄰點法):
步驟1:從一對雙親中隨機地選取一個城市最為開始城市,
步驟2:由當前城市出發,選擇一條不構成迴圈的最短邊(由雙親表達的)。若兩邊都構成迴圈,則隨機選取一個能使巡迴繼續的城市;
步驟3:如巡迴完成,停機;否則轉第2步。
啟發式交叉法明顯優於其他方法
三 染色體變異
本課題中的染色體變異使用的是啟發式變異,採用鄰域技術,以獲得後代的改進。啟發式變異過程如下:
步驟1:隨機地選出λ個基因;
步驟2:按所有選出基因的可能的換位產生鄰域;
步驟3:評估所有鄰域點,選出最好的作為變異產生的後代。
四 種群的適值函式
本課題中的適值函式為一個染色體中相鄰兩個基因的距離的加和,以及首尾兩個城市的距離。
五 種群的選擇策略
本課題中的選擇策略是從交叉後代,變異後代,和原來的父代中選擇最好的前n(n表示種群數量)個。
六 種群的初始化方法
本種群的初始化方法是從原始檔讀取城市資訊,確定城市數量,通過城市數量產生m(表示城市數量)個不同的隨機數,通過客戶的輸入的種群大小k,隨機產生k個染色體。
七 程式設計說明
1、遺傳演算法結構圖
2、種群初始化流程圖
3、染色體交叉流程圖
4、染色體變異流程圖
5、種群更新
八、程式
// 東北大學資訊科學與工程學院2000級碩士荊黎明
// 染色體的編碼方式:換位表達
// 染色體的交叉方式:啟發式交叉
// 染色體的變異方式:啟發式變異
// Created by jlm on 2020/10/19.
//
#include <iostream>
#include "class.h"
#include <ctime> // 產生隨機數種子
using namespace std;
int main()
{
PrintMessage();
srand(time(NULL)); // 設定隨機數種子
TSP tsp;
tsp.InitiPopul();
cout << "/*************************************種群開始迭代*************************************" << endl;
for (int i = 0; i != tsp.GetPopulationAlgebra(); i++)
{
cout << i+1 << "代" << endl << endl;;
tsp.Crossover();
tsp.HeuristicMutation();
tsp.Update();
tsp.Print();
cout << "/*************************************"<<i+1 << "代交叉變異結束" <<
"*************************************/" << endl;
}
return 0;
}
//
// Created by jlm on 2020/10/19.
//
#ifndef TSP_CLASS_H
#define TSP_CLASS_H
#include <iostream>
#include <string>
#include <vector>
using namespace std;
struct Data {
int PopulationAlgebra; // 種群代數
double NumPopulation; // 種群數量
double CrossoverRate; // 交叉率
double MutationRate; // 突變率
};
typedef struct city{
std::string name;
double x;
double y;
}p;
typedef struct DistTable{
double distance;
int table;
} DT;
// 輸出檔案資訊
void PrintMessage(void) ;
class BaseTsp{
public:
BaseTsp();
// 顯示路徑
void ShowRoute(vector<int> &vi) const;
// 獲得兩個城市的距離
double GetTwoCityDist(int firstCity, int secondCity) const;
// 獲得n個城市的路徑
void GetCityDist(const vector<int> &vi, double &distance) const;
// 生成隨機數
void GeneratorRand(vector<int> &vi) const;
// 獲得nCity資料
int GetnCity(void) const;
// 列印染色體
void printFunc(const vector<int> &vi) const;
private:
void ReadCityData();
vector<p> vCity;
int nCity;
};
class TSP: public BaseTsp
{
public:
TSP(int Size, double CrossoverRate, double MutationRate, int PopulationAlgebra);
TSP(struct Data data);
TSP();
void InitiPopul(void);
void Crossover(void);
void HeuristicMutation(void);
void Update(void);
void Print(void);
public:
// 獲得種群代數
int GetPopulationAlgebra(void) const;
private:
// 兩個父代產生一個子代
void GeneratorOffspring( const vector<int> &va, const vector<int> &vb, vector<int> &offspring) const;
// 確定定位點
int DeterminePoint(const vector<int> &vi, const int &value) const;
// 為種群生成一個隨機數列,該數列作為種群中各個染色體的交叉率 、變異率
void ForPopulRand(vector<double> &vd) const;
// 根據適值選擇變異的子代
void SelectOffspring(const vector<vector<int> > &mutoffspring, vector<int> &bestMuOffspring) const;
// 基因換位,傳入一個父代基因,輸出全排列後的所有基因
void GeneTransposition(const vector<int> &vpa, vector<vector<int> > &vvGene) const;
// 全排列演算法 傳入一個陣列,產生一個全排列陣列
void Permutation(vector<int> &vi, vector<int>::iterator begin,
vector<int>::iterator end, vector<vector<int> > &vvi) const;
// 生成n個不同的隨機數,範圍0~n;
void GeneratorRand(int n, int start, int end, vector<int> & vi) const;
// 對基因進行插值
void Interpolation(const vector<int> &position, const vector<int> &vGene, vector<vector<int> > &vvGene) const;
// 根據適值選擇子代,子代的個數為種群的數量
void SelectOffspring(vector<vector<int> > &vparent);
// 尋找最後一個元素是否前面出現過
bool findFun(vector<int> &vi) const;
int DeleteFun(vector<int> & vtParent, vector<int> & voffspring) const;
void InputData(struct Data & data) const;
private:
int Size; //種群數量
double CrossoverRate; //交叉率
double MutationRate; // 突變率
int PopulationAlgebra; // 種群迭代次數
vector<vector<int> > vParent; // 父代染色體
vector<vector<int> > vOffspring; // 交叉產生的染色體
vector<vector<int> > vMutOffspring; // 變異產生的染色體
};
#endif //TSP_CLASS_H
//
// Created by jlm on 2020/10/19.
//
#include "class.h"
#include <iostream>
#include <fstream>
#include <cstdlib> // support for exit() //隨機數
#include <cmath>
#include <ctime> // 產生隨機數種子
#include <vector>
#include <algorithm> // for sort() 排序函式
using namespace std;
/*
* @BaseTsp()建構函式
*/
BaseTsp::BaseTsp()
{
ReadCityData();
}
/*
@ ReadCityDate() :實現檔案資料讀取
*/
void BaseTsp::ReadCityData()
{
cout << "Enter name of data file: ";
string filename;
cin >> filename;
ifstream file(filename);
if(!file.is_open())
{
cerr << "檔案未能開啟:" << filename << endl;
cerr << "程式終止\n";
exit(EXIT_FAILURE); // should include <cstdlib>
}
p City; // 城市的結構體
nCity = 0;
file >> City.name >> City.x >> City.y ;
while(file.good())
{
vCity.push_back(City);
nCity++;
file >> City.name >> City.x >> City.y ;
}
if(file.eof())
{
cout <<" 檔案資料資訊讀取完成.\n";
}
else if (file.fail())
{
cout << " 檔案資料資訊不匹配.\n";
}
else
{
cout << " 由未知原因導致程式輸入異常終止.\n";
}
file.close();
cout << "資料讀取完成..." << endl;
}
/*
* @ShowRoute:該函式實現輸出巡迴路徑
* @ vi : 染色體
*/
void BaseTsp::ShowRoute(vector<int> &vi) const
{
cout << "最優路徑: " ;
//向螢幕輸出結果
int num = 0;
for (auto a:vi)
{
cout << vCity[a - 1].name << "->" ;
num++;
if(num % 20 == 0) // 20個城市換行
cout << endl;
}
cout << vCity[vi[0] - 1].name << endl;
}
/*
* @GetTwoCityDist():該函式實現兩個城市距離計算
* @返回值:兩個城市間的距離
* @firstCity: 第一個城市的序號
* @secondCity: 第二個城市的序號
*/
double BaseTsp::GetTwoCityDist(int firstCity, int secondCity) const
{
double distance;
distance = sqrt((vCity[firstCity - 1].x - vCity[secondCity - 1].x)*(vCity[firstCity - 1].x - vCity[secondCity - 1].x)
+(vCity[firstCity - 1].y - vCity[secondCity - 1].y)*(vCity[firstCity - 1].y - vCity[secondCity - 1].y));
return distance;
}
void BaseTsp::GetCityDist(const vector<int> &vi, double &distance) const
{
distance = 0;
int n = vi.size();
for (int i = 0; i < n - 1; i++)
{
distance += GetTwoCityDist(vi[i], vi[i+1]);
}
// 最後回到原點
distance += GetTwoCityDist(vi[n - 1], vi[0]);
}
/*
*@GetnCity:獲得城市的數量
*/
int BaseTsp::GetnCity(void) const
{
return nCity;
}
/*
* @GeneratorRand:為染色體產生隨機數,隨機數範圍位【1,城市的數量】
* @vi: 染色體
*/
void BaseTsp::GeneratorRand(vector<int> &vi) const // for chromosome(染色體)
{
int numCity = GetnCity();
int randNum;
int j;
for (int i = 0; i < numCity; i++)
{
while(1)
{
randNum = rand() % numCity + 1; // 獲取固定區間[m,n]的隨機數的公式 rand % (n - m + 1) + m
for (j = 0; j < i; j++)
if(vi[j] == randNum) break; // 檢查重複
if (j == i) // 沒有重複,儲存到vi中
{
vi.push_back(randNum);
break;
}
}
}
}
/*
* @printFunc(): 列印染色體
*/
void BaseTsp::printFunc(const vector<int> &vi) const
{
for (auto a:vi)
{
cout << a << " ";
}
cout << endl;
}
/*
* @TSP: TSP() 的建構函式
* @ Size: 種群的數量
* @ CrossoverRate: 種群的交叉率
* @ MutationRate: 種群的變異率
*/
TSP::TSP(int Size, double CrossoverRate, double MutationRate, int PopulationAlgebra):BaseTsp()
{
this -> Size = Size;
this -> CrossoverRate = CrossoverRate;
this -> MutationRate = MutationRate;
this -> PopulationAlgebra = PopulationAlgebra;
}
/*
* @TSP():建構函式
* @data: 結構體
*/
TSP::TSP( struct Data data):BaseTsp()
{
this -> Size = data.NumPopulation;
this -> CrossoverRate = data.CrossoverRate;
this -> MutationRate = data.MutationRate;
this -> PopulationAlgebra = data.PopulationAlgebra;
}
TSP::TSP() :BaseTsp()
{
struct Data data;
InputData(data);
this -> Size = data.NumPopulation;
this -> CrossoverRate = data.CrossoverRate;
this -> MutationRate = data.MutationRate;
this -> PopulationAlgebra = data.PopulationAlgebra;
}
/*
* @InitiPopul(): tsp的初始化函式,並列印產生的初始種群
*/
void TSP::InitiPopul(void)
{
for (int i = 0; i < Size; i++)
{
vector<int> vi;
BaseTsp::GeneratorRand(vi);
vParent.push_back(vi);
}
// 列印出初始種群
cout << "初始種群" <<endl;
int i = 0;
for (auto a:vParent)
{
cout << ++i << "# ";
printFunc(a);
}
}
/*
* @Crossover():種群交叉,並列印種群交叉產生的子代
*/
void TSP::Crossover(void)
{
vector<double> vd; // 儲存各個染色體的交叉率
ForPopulRand(vd);
// 尋找小於交叉率的染色體
vector<int> vc; // 儲存染色體小於交叉率的序號
for (int i = 0; i != vd.size(); i++)
{
if (vd[i] <= CrossoverRate)
{
vc.push_back(i);
}
}
if (vc.size()%2) // 刪除一個數,使得產生偶數個父代
{
int t = rand() % vc.size(); // 隨機產生一個數
vc.erase(vc.begin() + t);
}
// 隨機選擇兩個染色體進行交叉
int nNum = vc.size()/2; // 進行交叉的次數
for (int i = 0; i != nNum; i++)
{
int vaPoint = rand() % vc.size();
int vaValue = vc[vaPoint]; // 父代1號索引值
vc.erase(vc.cbegin() + vaPoint);
int vbPoint = rand() % vc.size();
int vbValue = vc[vbPoint]; // 父代2號索引值
vc.erase(vc.cbegin() + vbPoint);
vector<int> offspring; // 儲存交叉的子代
GeneratorOffspring(vParent[vaValue],vParent[vbValue],offspring);
vOffspring.push_back(offspring);
}
}
/*
* @GeneratorOffspring():兩個染色體進行交叉,產生子代染色體
* @va: 父代染色體
* @vb: 父代染色體
* @offspring: 交叉產生的子代染色體
*/
void TSP::GeneratorOffspring( const vector<int> &va, const vector<int> &vb,
vector<int> &offspring) const
{
int nCity = GetnCity();
int firstCity = rand() % nCity + 1; // 隨機選擇一個城市作為開始,隨機數的產生範圍為[1, ncity]
offspring.push_back(firstCity); // 第一個基因
int vaPoint, vbPoint;
int count = 0;
vaPoint = DeterminePoint(va, firstCity);
vbPoint = DeterminePoint(vb, firstCity);
vector<int> vtParent(va.begin(),va.end());
while (offspring.size() != nCity)
{
if (vaPoint == nCity - 1)
{
vaPoint = -1;
}
if (vbPoint == nCity - 1)
{
vbPoint = -1;
}
double distanceOne = GetTwoCityDist(offspring[offspring.size() - 1],va[vaPoint + 1]);
double distanceTwo = GetTwoCityDist(offspring[offspring.size() - 1], vb[vbPoint + 1]);
if (distanceOne >= distanceTwo)
{
offspring.push_back(vb[vbPoint + 1]);
if (findFun(offspring)) //最後一個元素和前面的基因(元素)重複
{
offspring.push_back(va[vaPoint + 1]);
if(findFun(offspring))
{
//隨機選擇一個城市
int city = DeleteFun(vtParent, offspring);
offspring.push_back(city);
vaPoint = DeterminePoint(va, city);
vbPoint = DeterminePoint(vb, city);
}
else
{
vaPoint = vaPoint + 1;
vbPoint = DeterminePoint(vb, va[vaPoint]);
}
}
else
{
vaPoint = DeterminePoint(va, vb[vbPoint + 1]);
vbPoint = vbPoint + 1;
}
}
else
{
offspring.push_back(va[vaPoint + 1]);
if (findFun(offspring))
{
offspring.push_back(vb[vbPoint + 1]);
if (findFun(offspring))
{
// 隨機選擇一個城市
int city = DeleteFun(vtParent, offspring);
offspring.push_back(city);
vaPoint = DeterminePoint(va, city);
vbPoint = DeterminePoint(vb, city);
}
else
{
vaPoint = DeterminePoint(va, vb[vbPoint + 1]);
vbPoint = vbPoint + 1;
}
}
else
{
vaPoint = vaPoint + 1;
vbPoint = DeterminePoint(vb, va[vaPoint]);
}
}
}
}
/*
* @DeleteFun():刪除新增的重複城市,並隨機選擇一個城市
* @vtParent: 父代
* @voffspring: 子代
*/
int TSP::DeleteFun(vector<int> & vtParent, vector<int> &voffspring) const
{
for (int i = 0; i != voffspring.size(); i++)
{
for (int j = 0; j != vtParent.size(); j++)
{
if (voffspring[i] == vtParent[j])
{
vtParent.erase(vtParent.begin() + j);
j = j - 1;
}
}
}
int cityPoint = rand() % vtParent.size() + 1;
return vtParent[cityPoint - 1];
}
/*
*@ findFun : 查詢染色體中前面已經出現的城市,若出現則刪除
*/
bool TSP::findFun( vector<int> &vi) const
{
for (int i = 0; i != vi.size()- 1; i++) // 減去2的原因是value
{
if (vi[i] == vi[vi.size() - 1])
{
vi.erase(vi.cbegin() + vi.size() - 1);
return true;
}
}
return false;
}
/*
* @DeterminePoint():該函式的功能是確定value值在染色體的vi的位置
* @ vi: 染色體
* @ value: 染色體的某個值
*/
int TSP::DeterminePoint(const vector<int> &vi, const int &value) const
{
for (int i = 0; i != vi.size(); i++)
{
if (value == vi[i])
{
return i;
}
}
}
/*
@function :函式功能為為種群生成一個隨機數列,該隨機數列可作為交叉率和突變率
@ vd : vd儲存的是生成的隨機數列
*/
void TSP::ForPopulRand(vector<double> &vd) const
{
srand(time(NULL));
double randNum;
const int N = 99; // 兩位小數
for (int i = 0; i < Size; i++)
{
randNum = rand() %(N + 1)/(double) (N + 1); // 生成0-1間的隨機數
vd.push_back(randNum);
}
}
/*
* @ HeuristicMutation(): 該函式的動能是對染色體進行變異
*/
void TSP::HeuristicMutation(void)
{
// 第一步:根據突變率選擇變異的父代
vector<double> vd; // 儲存的是各個染色體的突變率
ForPopulRand(vd);
vector<int> vmu; // 儲存需要突變的染色體序號
for (int i = 0; i != vd.size(); i++)
{
if (vd[i] <= MutationRate)
{
vmu.push_back(i);
}
}
for (int i = 0; i != vmu.size(); i++)
{
vector<vector<int> > vvGene; // 儲存全排列後的所有染色體
GeneTransposition(vParent[vmu[i]], vvGene);
// 對於每個染色體選擇最優的子代
vector<int> bestMuOffspring;
SelectOffspring(vvGene, bestMuOffspring);
vMutOffspring.push_back(bestMuOffspring);
}
}
/*
@function:基因換位,傳入一個父代基因,輸出全排列後的所有染色體
@vpa: 表示父代基因
@vvGene: 表示生成的變異基因(已經除去了和父代相同的基因)
*/
void TSP::GeneTransposition(const vector<int> &vpa, vector<vector<int> > &vvGene) const
{
int numGene = rand() % (vpa.size() - 2) + 2; // 選擇numGene 個基因,範圍在[2~vpa.size()-1]
// 對n個基因位置進行插值
vector<int> vi; // vi 儲存變異基因的位置
GeneratorRand(numGene, 0, vpa.size() - 1, vi);
Interpolation(vi, vpa, vvGene);
}
// 對基因進行插值,生成基因全排列
/*
@ position : 儲存的是隨機選擇的基因位置
@ vGene : 傳入的父代基因
@ vvGene : 生成基因全排列
*/
void TSP::Interpolation(const vector<int> &position, const vector<int> &vGene, vector<vector<int> > &vvGene) const
{
vector<int> vTemp; // 裝載隨機選擇的基因
for (auto a:position)
{
vTemp.push_back(vGene[a]);
}
vector<int> vtemp(vTemp.begin(),vTemp.end());
// 對選擇的基因進行全排列
vector<vector<int> > vvgene; // 儲存選擇的基因的全排列
Permutation(vTemp, vTemp.begin(), vTemp.end(), vvgene);
// 刪除和原始基因一樣的序列
int numGene = vvgene.size();
for (auto it = vvgene.cbegin(); it != vvgene.cend(); it++)
{
for (int j = 0; j != (*it).size(); j++)
{
if((*it)[j] == vtemp[j])
{
if(j == (*it).size() - 1)
{
vvgene.erase(it);
}
}
else
{
break;
}
}
if(numGene != vvgene.size()) // 已經找到重複基因,跳出迴圈
{
break;
}
}
// 將生成的全排列陣列分配到基因中
vector<int> gene(vGene.begin(),vGene.end());
for (auto a:vvgene)
{
int i = 0;
for (auto b:a)
{
gene[position[i]] = b;
i++;
}
vvGene.push_back(gene);
}
}
/*
function: 該函式的功能是生成n個數的全排列
@vi:儲存的是需要進行全排列的n個數
@begin:儲存的是vi的首迭代器
@end: 儲存的是vi的尾迭代器
*/
void TSP::Permutation(vector<int> &vi, vector<int>::iterator begin,
vector<int>::iterator end, vector<vector<int> > &vvi) const
{
if (begin == end)//遞迴的基礎部分
{
vector<int> temp;
for (vector<int>::iterator it = vi.begin(); it != end; it++)
{
temp.push_back(*it);
}
vvi.push_back(temp);
}
else
{
for (auto it = begin; it != end; it++)
{
swap(*begin, *it);
Permutation(vi, begin+1, end, vvi);
swap(*begin, *it);
}
}
}
/*
@ n : 產生隨機數的個數
@ start :
@ end : [start end] 產生隨機數的範圍
@ vi :生成的隨機數 (儲存隨機選擇的基因位置)
*/
void TSP::GeneratorRand(int n, int start, int end, vector<int> &vi) const
{
int randNum;
int j;
for (int i = 0; i != n; i++)
{
while(1)
{
randNum = rand() % (end - start + 1) + start;
for (j = 0; j < i; j++)
{
if (vi[j] == randNum)
break;
}
if (j == i)
{
vi.push_back(randNum);
break;
}
}
}
}
/*
* @ Update():該函式的功能是更新種群
*/
void TSP::Update(void)
{
for (auto a:vOffspring)
{
vParent.push_back(a);
}
for (auto a:vMutOffspring)
{
vParent.push_back(a);
}
SelectOffspring(vParent);
}
/*
* @SelectOffspring(): 該函式的功能是選擇最優的染色體(選擇的數量是初始種群的個數)
* @ vparent: 需要進行選擇的種群
*/
void TSP::SelectOffspring(vector<vector<int> > &vparent)
{
vector<DT> vDT; // 儲存距離和標號
for (int i = 0; i != vparent.size(); i++)
{
DT dt;
GetCityDist(vparent[i], dt.distance);
dt.table = i;
vDT.push_back(dt);
}
sort(vDT.begin(),vDT.end(),
[]( struct DistTable &dtOne, struct DistTable &dtTwo){ return (dtOne.distance < dtTwo.distance);
});
for (int i = 0; i != vDT.size(); i++)
{
for (int j = i + 1; j != vDT.size(); j++)
{
if (vDT[i].distance == vDT[j].distance)
{
vDT.erase(vDT.begin() + i);
j = j - 1;
}
}
}
vector<vector<int> > VPARENT;
for (int i = 0; i != Size; i++)
{
VPARENT.push_back(vparent[vDT[i].table]);
}
vparent.clear(); // 刪除所有元素
for (auto a:VPARENT)
{
vparent.push_back(a);
}
}
/*
* Print(): 該函式的功能是列印種群的最優路徑和最優路徑距離
*/
void TSP::Print()
{
// cout << "交叉產生的後代" << endl;
// for (int i = 0; i != vOffspring.size(); i++)
// {
// cout << i+1 << "# ";
// printFunc(vOffspring[i]);
// }
// cout << "變異產生的後代" << endl;
// for (int i = 0; i != vMutOffspring.size(); i++)
// {
// cout << i+1 << "# ";
// printFunc(vMutOffspring[i]);
// }
vOffspring.clear(); // 刪除本代產生的交叉子代
vMutOffspring.clear(); // 刪除本代變異產生的子代
// cout << "物競天擇,適者生存後的種群" << endl;
// for (int i = 0; i != vParent.size(); i++)
// {
// cout << i+1 << "# ";
// printFunc(vParent[i]);
// }
vector<int> bestSoulation;
SelectOffspring(vParent, bestSoulation);
cout << "該種群中的最優解:" << endl;
printFunc(bestSoulation);
double distance ;
GetCityDist(bestSoulation, distance);
ShowRoute(bestSoulation);
cout << "該種群中的最短路徑為:" << distance << endl;
// 將distance儲存在CSV格式檔案中
static int start = 0;
ofstream oFile;
if (start == 0) // 第一代
{
oFile.open("distance.csv");
oFile << distance << endl;
oFile.close();
}
oFile.open("distance.csv", ofstream::app); // 為了保留檔案內容,必須顯示指定app模式
oFile << distance << endl;
oFile.close();
start++;
}
/*
@ function : 根據適值選擇最好的子代
@ mutoffspring : 變異基因的全排列組合
@ bestMuOffspring: 選擇出最好的子代
*/
void TSP::SelectOffspring(const vector<vector<int> > &mutoffspring, vector<int> &bestMuOffspring) const
{
vector<double> vd; // 儲存城市路徑的總距離
for (auto a:mutoffspring)
{
double distance;
GetCityDist(a,distance);
vd.push_back(distance);
}
double min = vd[0];
int minKpoint = 0;
for (int i = 0; i != vd.size(); i++)
{
if (vd[i] <= min)
{
minKpoint = i;
}
}
for (auto a:mutoffspring[minKpoint])
{
bestMuOffspring.push_back(a);
}
}
int TSP::GetPopulationAlgebra(void) const
{
return (PopulationAlgebra);
}
void TSP::InputData(struct Data & data) const
{
cout << "請輸入資料資訊:種群代數,種群數量,種群交叉率,種群突變率等" << endl << endl;
cout << "種群代數: " ;
cin >> data.PopulationAlgebra;
cout << "種群數量:";
cin >> data.NumPopulation;
cout << "種群交叉率:";
cin >> data.CrossoverRate;
cout << "種群突變率:";
cin >> data.MutationRate;
}
/*
* @PringMessage(): 該函式的功能是列印程式資訊
*/
void PrintMessage(void)
{
cout << "學校:東北大學" << endl;
cout << "學院:資訊科學與工程學院" << endl;
cout << "專業:控制科學與工程" << endl;
cout << "學號:2000764" << endl;
cout << "班級:2005班" << endl;
cout << "姓名:荊黎明" << endl;
cout << endl << endl;
cout << "注:" << endl;
cout << "本程式的除錯工作是在Ubuntu18.04上完成的!!!" << endl;
cout << "染色體的編碼方式:換位表達" << endl;
cout << "染色體的交叉方式:啟發式交叉" << endl;
cout << "染色體的變異方式:啟發式變異" << endl;
cout << endl << endl;
}
相關文章
- 啟發式合併
- A*啟發式搜尋
- Android啟發式尋路Android
- 樹上啟發式合併
- A*與“一般的啟發式”
- sigmod啟用函式和梯度消失問題函式梯度
- vue函式元件,slot分發,只實現default slot的問題Vue函式元件
- 樹上啟發式合併總結
- 人工智慧 (09) 啟發式搜尋人工智慧
- SOAR的啟發式規則建議
- 樹上啟發式合併-附有例題CF600E
- mysql隱式轉換問題MySql
- Java開發桌面程式學習(十)——css樣式表使用以及Button懸浮改變樣式實現JavaCSS
- C++實現進位制轉換工具C++
- RUI:受 SwiftUI啟發的實驗性宣告式Rust UI庫UISwiftRust
- 旅行商問題(TSP)概述
- 虛擬函式表-C++多型的實現原理函式C++多型
- 分散式鎖實現的正確開啟方式分散式
- [分散式]高併發案例---庫存超發問題分散式
- Just for fun——C/C++函式返回區域性變數的問題C++函式變數
- dsu on tree (樹上啟發式合併) 詳解
- PostgreSQL LIST分割槽實現:繼承表+函式+觸發器。SQL繼承函式觸發器
- AppDomain實現【外掛式】開發APPAI
- redis實現分散式鎖---實操---問題解決Redis分散式
- 用分散式鎖解決併發問題分散式
- Flink flatMap 使用lambda表示式異常問題
- 無意中發現頁面中有隱藏的樣式BUG問題
- 【C++】禁止隱式轉換C++
- C++實現任意進位制的相互轉換C++
- 樹上啟發式合併(dsu on tree)學習筆記【理解+模板+例題】筆記
- zoj-4053(2018ICPC青島網路賽K題)啟發式分裂
- HDU7458-啟發式合併最佳化DP
- .NET Core中外掛式開發實現
- c++字串查詢函式實現C++字串函式
- [20220811]奇怪的隱式轉換問題.txt
- 面試常見問題之實現bind函式面試函式
- [python] 啟發式演算法庫scikit-opt使用指北Python演算法
- DDD關鍵系統啟發式思考的入門 - wulrich