遗传算法求解百人运动校园最短路径

问题描述

实现过程

结果

实验源代码

#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(); // 进行迭代处理
}

  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值