问题描述
![](https://img-blog.csdnimg.cn/direct/2f977ca9ba884c30b7230085d1cd19f5.png)
![](https://img-blog.csdnimg.cn/direct/1101f19f560349a7a595abaaf55a4c47.png)
实现过程
![](https://img-blog.csdnimg.cn/direct/78906ec9dbc14384bb486af08cdbc614.png)
![](https://img-blog.csdnimg.cn/direct/eb6c6fb7ca1842da9861c7783ac016ae.png)
![](https://img-blog.csdnimg.cn/direct/a9482cdfadcc4f8bbef0a9956117262a.png)
![](https://img-blog.csdnimg.cn/direct/b2365d4139f8470aa221b6a1f256900f.png)
![](https://img-blog.csdnimg.cn/direct/16824ba77c9043e9a4d644ca719ec5d9.png)
结果
![](https://img-blog.csdnimg.cn/direct/4eab00b4c46c4f2da2ab1fa219db0ef4.png)
![](https://img-blog.csdnimg.cn/direct/01c15e60b3304c3996df9eda3b76945d.png)
![](https://img-blog.csdnimg.cn/direct/64a7b3dc9384472aa1122a0a743eca58.png)
实验源代码
#include <iostream>
#include <vector>
#include <set>
#include <map>
#include <ctime>
#include <random>
using namespace std;
int N = 50; // 人的数目
int gene_count = 200;
vector<vector<int>> points(N, vector<int>(5, 0)); // 人的点位
vector<vector<int>> matrix; // 基因串
vector<vector<int>> matrix400; // 400个子代基因
vector<vector<double>> dist(N * 5, vector<double>(N * 5, 0)); // 距离矩阵.
vector<double> cost(gene_count * 2, 0); // 400个基因路径长度
double cross_rate = 50; // 交叉率
double mutation_rate = 50 - cross_rate; // 变异率
double ans = 1e6; // 最终结果
vector<int> ans_list;
/**
* 初始化点位矩阵
*/
void init_point()
{
int num = 0;
for (int i = 0; i < N; i++)
{
for (int j = 0; j < 5; j++)
{
points[i][j] = num++;
}
}
}
/**
* 生成串
*/
void generate()
{
// 生成基因串
// srand(time(0));
set<vector<int>> st2; // 防止基因串重复
while (matrix.size() < gene_count)
{
set<int> st; // 一个人
vector<int> index(N, 0); // 对应串的指针
vector<int> list;
while (1)
{
int ii;
// 找还有剩余点的人
while (1)
{
ii = rand() % N;
// ii = u(e);
if (!st.count(ii))
{
break;
}
}
int k = index[ii]++;
list.push_back(points[ii][k]);
if (index[ii] == 5)
{ // 这个人的所有点位已经加入到list中
st.insert(ii);
}
if (st.size() == N)
{
if (!st2.count(list))
{
matrix.push_back(list); // 添加到matrix中
st2.insert(list);
}
break;
}
}
}
// 输出基因串
cout << gene_count << "父代基因串中的其中10个:" << endl;
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < N * 5; j++)
{
cout << matrix[i][j] << ' ';
}
cout << endl;
}
}
/**
* 适应度计算 : 就是路程的计算
*/
void fitness()
{
// 计算400个子代的cost值
for (int i = 0; i < gene_count * 2; i++)
{
vector<int> ver = matrix400[i];
double sum = 0;
for (int j = 0; j < N * 5 - 1; j++)
{
int x = matrix400[i][j];
int y = matrix400[i][j + 1];
sum += dist[x][y];
}
cost[i] = sum; // 赋值
// 保存最优解
if (cost[i] < ans)
{
ans_list = ver;
ans = cost[i];
}
}
// 排序 : 冒泡排序
for (int i = 0; i < gene_count * 2 - 1; i++)
{
for (int j = 0; j < gene_count * 2 - i - 1; j++)
{
if (cost[j] > cost[j + 1])
{
int t = cost[j];
auto ver = matrix400[j];
cost[j] = cost[j + 1];
matrix400[j] = matrix400[j + 1];
cost[j + 1] = t;
matrix400[j + 1] = ver;
}
// cout << "排序中" << endl;
}
}
// 排序完之后, 取400个中的前200个
for (int i = 0; i < gene_count; i++)
{
matrix[i] = matrix400[i];
}
}
/**
* 检查基因的合法性
*/
bool check(vector<int> ver)
{
int n = ver.size();
set<int> st;
st.insert(ver[0]); // 第一个点是合法的
for (int i = 1; i < n; i++)
{
int x = ver[i];
// x已经跑过了
if (st.count(x))
{
return false;
}
int md = x / 5; // 求出这是哪个人的点位, 是除法
int y = md * 5;
while (y < x)
{ // x点位能加入的前提是, x之前的都已经加入了
if (!st.count(y))
{ // 不在
return false;
}
y++;
}
st.insert(x); // 点位x进入。
}
return true;
}
/**
* 交叉
*/
void crossover()
{
// srand(time(0));
int index = rand() % (N * 5); // 交叉的点
int ii = 0, jj = 0;
while (ii == jj)
{
ii = rand() % N;
jj = rand() % N; // 交叉的两个串
}
auto list1 = matrix[ii], list2 = matrix[jj];
auto list11 = list1, list22 = list2;
/**
* 交换一段
*/
for (int i = 0; i <= index; i++)
{
// 交叉
int t = list1[i];
list1[i] = list2[i];
list2[i] = t;
}
if (check(list1))
{
// cout << "交换前" << endl;
// for (auto x : list11)
// cout << x << ' ';
// cout << endl;
// // 交换后
// cout << "成功交换" << endl;
// for (auto x : list1)
// cout << x << ' ';
// cout << endl;
matrix400.push_back(list1);
}
if (check(list2))
{
matrix400.push_back(list2);
}
}
/**
* 变异
*/
void mutation()
{
// 变异的点的下标
// srand(time(0));
int idx = -1;
while (!(idx < N * 5 - 1 && idx >= 0))
idx = rand() % N * 5;
// 变异的基因
int ii = rand() % N;
auto list = matrix[ii];
// cout << "变异前" << endl;
// for (auto x : list)
// cout << x << " ";
// cout << endl;
swap(list[idx], list[idx + 1]);
if (check(list))
{
matrix400.push_back(list);
// cout << "变异成功" << endl;
// for (auto x : list)
// cout << x << " ";
// cout << endl;
}
}
void iteration_1()
{
auto matrix_tmp = matrix;
while (1)
{
matrix = matrix_tmp;
ans = 1e6;
int T; // 迭代次数
cout << endl;
cout << "请输入要迭代的次数 T" << endl;
cin >> T;
int T2 = T;
while (T--)
{
matrix400 = matrix;
// cout << "T" << endl;
while (matrix400.size() < gene_count * 2)
{
int x = rand() % 100 + 1;
// 交叉
if (x <= cross_rate)
{
crossover();
}
// 变异
else
{
mutation();
}
}
fitness();
cout << "第" << (T2 - T) << "次迭代 : " << cost[0] << endl;
}
cout << "最优的基因串是 : ";
for (auto x : ans_list)
cout << x << ' ';
cout << endl;
cout << "最短路径是: " << ans << endl;
}
}
/*
* 生成距离矩阵
*/
void init_dist()
{
int n;
n = N;
srand(time(0));
for (int i = 0; i < n * 5; i++)
{
for (int j = 0; j <= i; j++)
{
// 生成随机浮点数
int x = rand() % 20 + 50;
double y = x / 10.0;
dist[i][j] = dist[j][i] = y;
}
}
// for (int i = 0; i < n * 5; i++)
// {
// cout << '{';
// for (int j = 0; j < n * 5; j++)
// {
// cout << dist[i][j] << ',';
// }
// cout << "\b}, ";
// cout << endl;
// }
}
int main()
{
// 随机数种子
srand(time(0));
// 初始化点位的值
init_point();
init_dist();
// cout << "请输入要生成的父代基因串数目gene_count" << endl;
// cin >> gene_count;
// 生成基因串
generate();
iteration_1(); // 进行迭代处理
}