2018.05.01:修改源代码170行(添加float),double RateVariation = float(rand()%100)/100;
【旅行商问题】旅行商问题(TravelingSalesmanProblem,TSP)是一个经典的组合优化问题。经典的TSP可以描述为:一个商品推销员要去若干个城市推销商品,该推销员从一个城市出发,需要经过所有城市后,回到出发地。应如何选择行进路线,以使总的行程最短。从图论的角度来看,该问题实质是在一个带权完全无向图中,找一个权值最小的Hamilton回路。由于该问题的可行解是所有顶点的全排列,随着顶点数的增加,会产生组合爆炸,它是一个NP完全问题。由于其在交通运输、电路板线路设计以及物流配送等领域内有着广泛的应用,国内外学者对其进行了大量的研究。早期的研究者使用精确算法求解该问题,常用的方法包括:分枝定界法、线性规划法、动态规划法等。但是,随着问题规模的增大,精确算法将变得无能为力,因此,在后来的研究中,国内外学者重点使用近似算法或启发式算法,主要有遗传算法、模拟退火法、蚁群算法、禁忌搜索算法、贪婪算法和神经网络等。【百度百科】
旅行商求解系列:
-------------------------------------------------------------------------------------------------
(1)TSP_旅行商问题- 蛮力法( 深度遍历优先算法DFS )
(2)TSP_旅行商问题- 动态规划
(3)TSP_旅行商问题- 模拟退火算法
(4)TSP_旅行商问题- 遗传算法
(5)TSP_旅行商问题- 粒子群算法
(6)TSP_旅行商问题- 神经网络
-------------------------------------------------------------------------------------------------
#define CITY_NUM 150 // TSP_城市个数
#define GROUP_NUM 30 // 群体规模
#define SON_NUM 32 // 产生儿子的个数 SON_NUM = GROUP_NUM + 2
const double P_INHERIATANCE = 0.01; // 变异概率
const double P_COPULATION = 0.8; // 杂交概率
const int ITERATION_NUM = 1500; // 遗传次数(迭代次数)
const double MAX_INT = 9999999.0;
typedef struct{
int vex_num, arc_num; // 顶点数 边数
int vexs[CITY_NUM]; // 顶点向量
double arcs[CITY_NUM][CITY_NUM]; // 邻接矩阵
}Graph;
typedef struct{
double length_path;
int path[CITY_NUM];
double P_Reproduction;
}TSP_solution;
void InitialGroup(Graph G){
cout<<"----------------------【遗传算法参数】-----------------------"<
void TSP_Evolution(Graph G){
/* */
int iter = 0;
while(iter < ITERATION_NUM){
// cout<<"***********************【第次"<<(iter + 1)<<"迭代】*************************"< 自交( 父母为同一个个体时, 母亲重新选择, 直到父母为不同的个体为止 )
cout<<"Warning!【Father_index = Mother_index】"<= 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 = "<
// 选择
/*
输入:当前总群
输出:按照一个评价, 随机从当前总群筛选出杂交对象, 本程序每次返回一个个体
选择方案:比例选择规则, [轮盘赌选择]
机制:反映在对父代种群中每一个体所赋予的允许繁殖概率及其从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 = "<
// 交叉
/*
输入:[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<<"[ 杂交过程的随机数产生有问题... ]"<
// 变异
/*
输入:杂交得到的所有个体(大于总群规模)
输出:通过变异策略, 以一定的变异概率(确定变异个数)随机选择个体进行变异
变异策略:随机交换染色体的片段, 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;
}
}
}
// 更新
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);
}
// 处理对象:每次新产生的群体, 计算每个个体的概率
// 问题:解决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;
}
}
/*
// 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];
}
}
}
TSP_solution Handle_Conflict(Graph G, TSP_solution ConflictSolution, int *Detection_Conflict, int *Model_Conflict, int Length_Conflict){
/*
cout<<"[ Handle_Conflict ]"< ";
}
cout< 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 = "<10. 计算程序耗时:
#include
int main(){
time_t T_begin = clock();
// 耗时程序段
time_t T_end = clock();
double RunningTime = double(T_end - T_begin) / CLOCKS_PER_SEC;
cout<
遗传算法相关参数 | 经验值 |
总群规模M | 20 -- 100 |
交叉概率 | 0.4 -- 0.99 |
变异概率 | 0.0001 -- 0.1 |
遗传过程的迭代次数 | 100 -- 1000 |
#ifndef _GA_H_
#define _GA_H_
#define CITY_NUM 150 // TSP_城市个数
#define GROUP_NUM 30 // 群体规模
#define SON_NUM 32 // 产生儿子的个数 SON_NUM = GROUP_NUM + 2
const double P_INHERIATANCE = 0.01; // 变异概率
const double P_COPULATION = 0.8; // 杂交概率
const int ITERATION_NUM = 1500; // 遗传次数(迭代次数)
const double MAX_INT = 9999999.0;
typedef struct{
int vex_num, arc_num; // 顶点数 边数
int vexs[CITY_NUM]; // 顶点向量
double arcs[CITY_NUM][CITY_NUM]; // 邻接矩阵
}Graph;
typedef struct{
double length_path;
int path[CITY_NUM];
double P_Reproduction;
}TSP_solution;
TSP_solution TSP_Groups[GROUP_NUM]; // 存储群体
TSP_solution Son_solution[SON_NUM]; // 存储杂交后的个体
int Length_SonSoliton = 0; // 遗传产生的孩子的个数
void CreateGraph(Graph &G);
void InitialGroup(Graph G);
double CalculateLength(Graph G,TSP_solution newSolution);
void TSP_Evolution(Graph G); // 模拟生物进化 - 解决TSP问题
int Evo_Select(Graph G); // 选择函数
void Evo_Cross(Graph G, TSP_solution TSP_Father, TSP_solution TSP_Mother); // 杂交函数
void Evo_Variation(Graph G, int Index_Variation); // 变异函数
void Evo_UpdateGroup(Graph G);
void TSP_Evaluate(Graph G); // TSP - 评价函数
int *Get_Conflict(int Conflict_Father[], int Conflict_Mother[], int Length_Cross, int &Length_Conflict); // 返回冲突的数组
TSP_solution Handle_Conflict(Graph G, TSP_solution ConflictSolution, int *Detection_Conflict, int *Model_Conflict, int Length_Conflict); // 解决冲突
void Calc_Probablity(Graph G, double total_length); // 计算概率
bool Check_path(Graph G, TSP_solution CurrentSolution);
void Display(Graph G);
#endif
#include
#include
#include // 本文用于输出对齐
#include
#include
#include
#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<> 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<<"无向图创建完毕,相关信息如下:"< 自交( 父母为同一个个体时, 母亲重新选择, 直到父母为不同的个体为止 )
// cout<<"Warning!【Father_index = Mother_index】"<= 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 = "< ";
}
cout< IndexCross_j)
{
int temp = IndexCross_i;
IndexCross_i = IndexCross_j;
IndexCross_j = temp;
}
if (IndexCross_j == CITY_NUM || IndexCross_i == 0)
{
cout<<"[ 杂交过程的随机数产生有问题... ]"< 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 = "< ";
}
cout< TSP_Groups[i].length_path)
{
bsetSolution = TSP_Groups[i];
}
}
cout<<"当前最优个体 bsetSolution = ";
for (int i = 0;i < G.vex_num;i++)
{
cout< ";
}
cout<九、参考文献
- 胡妙娟,胡春,钱锋,遗传算法中选择策略的分析
- 本文相关代码以及数据:http://download.csdn.net/detail/houchaoqun_xmu/9740071
- 白话讲解遗传算法 (Genetic Algorithm):http://blog.chinaunix.net/uid-27105712-id-3886077.html
- Study on Fuzzy Classifier Based on Genetic Algorithm Optimization
- Feature Selection Based on Hybridization of Genetic Algorithm and Particle Swarm Optimization
- A genetic algorithm-based learning approach to understand customer satisfaction with OTA websites
- Boolean regulatory network reconstruction using literature based knowledge with a genetic algorithm optimization method