旅行商问题
一 染色体表达方式
染色体的表达方式采用换位表达,它是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、种群更新
八、程序
// 东北大学信息科学与工程学院2020级硕士荆黎明
// 染色体的编码方式:换位表达
// 染色体的交叉方式:启发式交叉
// 染色体的变异方式:启发式变异
// 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;
}