赞
踩
车辆路线问题(VRP):一定数量的客户,各自有不同数量的货物需求,配送中心向客户提供货物,由一个车队负责分送货物,组织适当的行车路线,目 标是使得客户的需求得到满足,并能在一定的约束下,达到诸如路程最短、成本最小、耗费时间最少等目的。
假设1:仅有1个配送中心,在某一时刻,所有负责配送的车同时从 配送中心出发,分别完成各自的配送任务后,再回到配送中心(送奶路线);
假设2:配送中心有若干辆车(如6辆),一辆车可负责一个或多个点的配送任 务,且每个配送点只被服务一次。
假设3:每辆车有一定的载重量(如90t)和里程限制(如 200km),车的载重和行驶里程不可超过指定的值。
假设4:车辆必须在客户允许的时间窗处进行配送服务,此处采用硬时间窗
对于此问题,采用自然数编码,每个自然数代表一个客户,0代表配送中心,例如:
2 | 5 | 8 | 3 | 7 | 1 | 9 | 4 | 6 | 10 |
在解码过程中应该使每辆车在满足各种约束条件下为尽可能多的客 户提供服务。首先,安排第一辆车从配送中心0出发,到序列中的第一 个客户2处为其提供服务,服务完后再综合考虑车辆容量限制、行驶总路程限制以及序列中第二个客户5的时间窗限制等条件,决定是否直接到客户5处提供服务。 假若条件允许,则到客户5处,服务完再分析是否直接到客户8处提 供服务,依次类推;假若不能为客户8提供服务,则该辆车直接由客户5处返回配送中心,形成一个配送回路0->2->5->0。
接下来,安排第二辆车从配送中心0出发,直接到客户8处,服务完 再分析是否到后续客户3处为其服务。
依此类推,直到所有的客户都被服务为止,将客户序列拆分成了若 干个满足约束条件的配送回路,对应一个可行解。
注:为了使任何一个个体解码后都能对应可行解,本节假设从配送中心派一辆车单独为某一个客户提供服务,都可以在该客户的第一个时间窗内到达并完成服务。在实际中,假若从配送中心出发的车辆直接到 某个客户处服务,不能在该客户的第一个时间窗内完成服务,则说明该客户的第一个时间窗不可用,可以删掉该时间窗。因此,这种假设是有 意义的。
本程序可以调节是否可用交叉和变异,及其参数值,以及锦标赛法选取的后代数目可在参数设置区进行调节(默认0.1倍种群大小) ,仅仅将下面的两个数据文件与GA.cpp文件放在一个工程目录下即可运行代码。
设有一配送中心为10个客户提供货物配送服务,序号0表示配送中心, 序号1,2,…,10表示10个需求点。
配送中心共有6辆同型号的车辆,每辆车的最大装载量均为90t,每辆车的最长行驶距离均200km;
动用每辆车的固定成本均为50元,每辆车行驶每公里成本为20元;
配送中心及各个需求点之间的距离见表1;
车辆在配送中心及各个需求点之间的行驶时间见表2;
各个需求点的需求量、服务时间及可利用的时间窗见表3;
为了使总配送成本达到最少,需要安排多少辆车完成配送任务?每辆车的配送路径是什么?
随机遍历抽样是轮盘选择的修改版本。使用相同的轮盘,比例相同,但使用多个选择点,只旋转一次转盘就可以同时选择所有个体。 这种选择方法可以防止个体被过分反复选择,从而避免了具有特别高适应度的个体垄断下一代。因此,它为较低适应度的个体提供了被选择的机会, 从而减少了原始轮盘选择方法的不公平性。
在2点交叉中, 交换两个父代个体中交叉点之间的基因序列,并形成交叉映射关系, 再按照交叉映射关系对其他位点的基因进行变换,得到两个新个体。
上面的两个父代对于选定的交叉点可以形成如下交叉映射关系:
4—5、8—7、2—10、11—3。
按照这样的映射关系,交叉后得到两个新个体
采用一定的进化代数N作为终止规则,即当进化代数达到N时,终止计算,并把历代种群个出现的适应度最大的个体作为问题的最优解输出。
操作系统:windows10家庭版
IDE:Visual Studio 2022
CPU:Intel Core i7-10875H 2.3GHz 实际速度:约4.3Ghz
内存:16GB DDR4 2933MHz
- //Time.h
-
- #pragma once
- #include<stdexcept>
-
- // 时间窗类
- class Time
- {
- public:
- // 默认构造函数
- Time() :start{ 0 }, end{ 24 } {}
- Time(unsigned start_, unsigned end_) :start{ start_ }, end{ end_ } {}
- //运算符重载
- bool operator<=>(const Time& other_time_window)const = delete;
- bool operator==(const Time& other_time_window)const = default;
- const auto& operator[](size_t index)const
- {
- if (index == 0)return start;
- if (index == 1)return end;
- throw std::out_of_range{ " Time 对象下标越界!" };
- }
- unsigned start; // 起始时刻
- unsigned end; // 结束时刻
- };
- // Customer.h
- #pragma once
- #include<array>
- #include<vector>
- #include<compare>
-
- #include"Time.h"
-
- const size_t Window_num{ 2 }; // 时间窗个数
- // 客户类,包括配送中心
- class Customer
- {
- public:
- // 默认构造函数
- Customer();
- // 主构造函数
- Customer(unsigned number, unsigned requirement, double service_time, std::array<Time, Window_num> time_window);
- // 删除副本成员
- Customer(const Customer&) = delete;
- Customer& operator=(const Customer&) = delete;
- // 默认移动成员
- Customer(Customer&&)noexcept = default;
- Customer& operator=(Customer&&)noexcept = default;
- //运算符重载
- bool operator==(const Customer& other_customer) const { return m_number == other_customer.get_number(); }
- const auto& operator[](size_t index)const { return m_time_window.at(index); }
- auto& operator[](size_t index) { return const_cast<Time&>(std::as_const(*this)[index]); }
- // 类型转换
- operator size_t()const { return m_number; }
-
-
- // 访问器 //
-
- const unsigned get_number() const { return m_number; }
- const unsigned get_requirement() const { return m_requirement; }
- const double get_service_time() const { return m_service_time; }
- // 展示顾客属性
- void show_customer() const;
- // 获得与另一个顾客的距离
- unsigned get_distance(const size_t other_customer_number)const;
- unsigned get_distance(const Customer& other_customer)const;
- unsigned get_distance(const Customer* other_customer)const;
- // 判断是否在时间窗内
- double is_in_window(double time)const;
-
- // 访问器 //
-
- // 无更改器 //
-
- // 展示固有参数
- static void show_parameters();
-
- static const Customer Distribution_Center; // 配送中心
- inline static std::vector<std::vector<int> > Distance_Matrix{}; // 客户以及配送中心之间的距离矩阵
- inline static std::vector<Customer> Customer_Array{}; // 客户序列,一般只在初始化时添加,不可修改
- inline static int Size{}; // 配送中心+客户数
-
-
- private:
- unsigned m_number; // 序号
- unsigned m_requirement; // 需求量,单位t
- double m_service_time; // 服务用时
- std::array<Time, Window_num> m_time_window{}; // 时间窗
- };
- // Car.h
- #pragma once
-
- #include"Customer.h"
-
- // 车辆类
- class Car
- {
- public:
- // 主构造函数
- explicit Car(unsigned number) :m_number{ number } {}
- // 默认副本成员
- Car(const Car&) = default;
- Car& operator=(const Car&) = default;
- // 默认移动成员
- Car(Car&&)noexcept = default;
- Car& operator=(Car&&)noexcept = default;
- //运算符重载
- const Customer* operator[](int index)const;
- Customer* operator[](int index) { return const_cast<Customer*>(std::as_const(*this)[index]); }
- // 类型转换
- operator size_t()const { return m_number; }
-
- // 访问器 //
-
- unsigned get_cost()const { return m_cost; }
- // 展示车辆属性
- void show_car()const;
-
- // 访问器 //
-
-
- // 更改器 //
-
- // 在路线后添加一个客户
- bool add_customer(const Customer* customer);
- //void add_customer(const Customer& customer);
- // 在时刻表后添加对应的时刻
- //void add_time(double time) { m_time.push_back(time); }
- // 计算配送成本
- void calculate_cost();
- // 更新时刻表
- bool update_time_list();
-
- // 更改器 //
-
- // 展示固有参数
- static void show_parameters(int choice = 0);
-
- inline static unsigned Max_Amount{ 6 }; // 车辆最大数量
- inline static unsigned Max_Load{ 90 }; // 车辆载重量,单位t
- inline static unsigned Max_Distance{ 200 }; // 车辆最大行驶距离,单位km
- inline static unsigned Fixed_Cost{ 50 }; // 车辆固定成本
- inline static unsigned Variable_Cost{ 20 }; // 车辆单位距离行驶成本
- inline static std::vector<std::vector<double> > Time_Matrix{}; // 汽车配送时间矩阵
-
- private:
- unsigned m_number; // 车辆汽车序号
- unsigned m_load{}; // 车辆车实际载重量
- unsigned m_distance_traveled{}; // 车辆车实际行驶距离
- std::vector<const Customer*> m_route{}; // 车辆车所经过的路径数组,包括出发和返回配送中心
- std::vector<double> m_time{}; // 车辆车到达时刻,与路径数组大小相同
- int m_customer_number{}; // 车辆车路径经过的客户数
- unsigned m_cost{}; // 车辆车成本,包括变动和固定成本
- };
- //Individual.h
- #pragma once
-
- #include"Car.h"
- // 个体类
- class Individual
- {
- public:
- // 默认构造函数
- Individual() :m_DNA{}, m_fitness{}, m_genetic_probability{}, m_sum_probability{}, m_cost{ 999999 }, m_number_of_violations{ 999999 } {}
- // 主构造函数
- Individual(const std::vector<int>& dna, unsigned cost = 0, std::vector<Car> car_array = std::vector<Car>{}, unsigned number_of_violations = 0);
- // 运算符重载
- const int& operator[](size_t index)const { return m_DNA.at(index); }
- int& operator[](size_t index) { return const_cast<int&>(std::as_const(*this)[index]); }
-
- // 访问器 //
-
- const auto& get_DNA()const { return m_DNA; }
- const unsigned get_cost()const { return m_cost; }
- const double get_fitness()const { return m_fitness; }
- const double get_genetic_probability()const { return m_genetic_probability; }
- const double get_sum_probability()const { return m_sum_probability; }
- const unsigned get_number_of_violations()const { return m_number_of_violations; }
-
- // 访问器 //
-
-
- // 更改器 //
-
- auto& set_DNA() { return m_DNA; }
- void update_fitness() { m_fitness = 1.0/m_cost; }
- void multiply_fitness(double value, unsigned times) { m_fitness *= pow(value, times); }
- void set_genetic_probability(double probability) { m_genetic_probability = probability; }
- void set_sum_probability(double sum_probability) { m_sum_probability = sum_probability; }
-
- // 解码
- void decode();
- // 更新并展示解
- void Update_and_display_solutions();
- // 计算成本
- unsigned update_cost();
- // 展示个体
- void show_individual()const;
-
- // 更改器 //
-
- static std::vector<Individual> Best_Individuals; // 最优个体,包括多个
-
- private:
-
- std::vector<int> m_DNA; // 基因序列
- double m_fitness; // 适应度,为成本的倒数
- double m_genetic_probability; // 遗传概率
- double m_sum_probability; // 轮盘赌累加值,左闭右开区间时,该个体成功遗传子代
-
- // 性状 //
- unsigned m_cost; // 成本
- std::vector<Car> m_car_array{}; // 电动车序列
- unsigned m_number_of_violations; // 违法约束次数
- // 性状 //
- };
- // Genetic_Algorithm.h
- #pragma once
-
- #include<string>
-
- #include"Individual.h"
-
-
- // 遗传算法类
- class Genetic_Algorithm
- {
- public:
- // 默认构造函数
- Genetic_Algorithm() = default;
- // 删除副本成员
- Genetic_Algorithm(const Genetic_Algorithm&) = delete;
- Genetic_Algorithm& operator=(const Genetic_Algorithm&) = delete;
- // 默认移动成员
- Genetic_Algorithm(Genetic_Algorithm&&)noexcept = default;
- Genetic_Algorithm& operator=(Genetic_Algorithm&&)noexcept = default;
-
-
- // 初始化种群
- void initialize();
-
- // 获得适应度
- void get_fitness();
- // 获得遗传概率
- void get_genetic_probability();
- // 获得轮盘赌累加概率
- void get_sum_probability();
-
- // 遗传算子 //
-
- // 选择算子,轮盘赌多选法
- void selection();
- // 交叉算子,两点交叉+映射法
- void crossover();
- // 变异算子,两点交换变异
- void mutation();
-
- // 遗传算子 //
-
- // 遗传算法入口
- void genetic_algorithm();
-
- // 展示固有参数
- static void show_parameters(int choice = 0);
-
-
-
- inline static size_t Po_Size{ 512 }; // 种群规模,一般为20~300
- inline static size_t Iterations{ 512 }; // 进化代数,一般为100~500
- inline static double Crossover_P{ 0.5 }; // 交叉概率,一般为0.4~0.99
- inline static double Mutation_P{ 1.0/1024 }; // 变异概率,一般为0.001~0.2
- inline static const double Punish{ 0.125 }; // 惩罚系数
- static Individual Best_Individual_in_History; // 历史最优个体
-
- private:
- std::vector<Individual> m_population{}; // 种群
-
-
- };
- //UI_Manage.h
- #pragma once
-
- #include"Genetic_Algorithm.h"
-
- class UI_Manage
- {
- public:
- // 展示菜单
- void Show_Menu()const;
- // 退出程序0
- void exit_system()const { exit(0); }
-
- // 读取文件1
- bool read_file(std::string_view distance_file = "节点距离.txt", std::string_view time_file = "行驶时间.txt", std::string_view customer_file = "客户需求和服务时间.txt");
-
- // 展示所有参数2
- void show_all_parameters()const;
-
- // 展示文件路径3
- void show_file_path()const;
-
- // 开始求解4
- void start_solve(std::string_view distance_file = "节点距离.txt", std::string_view time_file = "行驶时间.txt", std::string_view customer_file = "客户需求和服务时间.txt");
-
- // 修改参数5
- void modify_parameters();
-
- private:
-
- bool m_file_read{ false };
- };
- //Customer.cpp
- #include "Customer.h"
-
- #include<iostream>
- #include<format>
-
- using
- std::array,
- std::cout, std::endl,
- std::format;
-
- const Customer Customer::Distribution_Center{};
-
- // 默认构造函数
- Customer::Customer() :m_number{}, m_requirement{}, m_service_time{}, m_time_window{} {}
- // 主构造函数
- Customer::Customer(unsigned number, unsigned requirement, double service_time, std::array<Time, Window_num> time_window)
- :m_number{number},
- m_requirement{ requirement },
- m_service_time{ service_time },
- m_time_window {time_window}
- {}
-
- // 访问器 //
-
- // 判断是否在时间窗内,不在,则返回负数
- double Customer::is_in_window(double time)const
- {
- if (time < (*this)[0][0])
- {
- // 在第一个窗口前
- return time - (*this)[0][0];
- }
- else if (time <= (*this)[0][1])
- {
- // 在第一个窗口
- return 0;
- }
- else if (time < (*this)[1][0])
- {
- // 在两窗口中
- return time - (*this)[1][0];
- }
- else if (time <= (*this)[1][1])
- {
- // 在第二个窗口
- return 0;
- }
- else
- {
- // 在第二个窗口后,不能调整
- return 1;
- }
- }
- // 展示顾客属性
- void Customer::show_customer() const
- {
- cout << format("|{:4}|{:4}|{:.2f}|{:>2}{:<2},{:>2}{:<2}|{:>2}{:<2},{:>2}{:<2}|",
- m_number, m_requirement, m_service_time,
- "[", m_time_window[0].start, m_time_window[0].end, "]",
- "[", m_time_window[1].start, m_time_window[1].end, "]");
- }
- // 获得与另一个顾客的距离
- unsigned Customer::get_distance(const size_t other_customer_number)const
- {
- return Distance_Matrix[this->m_number][other_customer_number];
- }
- unsigned Customer::get_distance(const Customer& other_customer)const
- {
- return this->get_distance(static_cast<size_t>(other_customer.m_number));
- }
- unsigned Customer::get_distance(const Customer* other_customer)const
- {
- return this->get_distance(static_cast<size_t>(other_customer->m_number));
- }
-
- // 访问器 //
-
- void Customer::show_parameters()
- {
- using std::vector;
- cout << format("{}{}\n", "配送中心 + 客户数:", Size);
- cout << format("{:^30}\n", "节点距离矩阵");
- if (Distance_Matrix.empty())
- {
- cout << "距离矩阵为空!\n";
- }
- else
- {
- for (const auto& row : Distance_Matrix)
- {
- for (const auto& distance : row)
- {
- cout << format("{:2} ", distance);
- }
- cout << endl;
- }
- }
- cout << format("{:^30}\n", "客户序列");
- if (Distance_Matrix.empty())
- {
- cout << "客户序列为空!\n";
- }
- else
- {
- for (const auto& customer : Customer_Array)
- {
- customer.show_customer();
- cout << endl;
- }
- }
-
- }
- // Car.cpp
- #include "Car.h"
-
- #include<iostream>
- #include<format>
-
- using
- std::cout,std::endl,
- std::format,
- std::vector;
-
- // 运算符重载
- const Customer* Car::operator[](int index)const
- {
- if (index >= 0)return m_route.at(index);
- else return m_route.at(0);
- }
-
- // 访问器 //
-
- // 展示车辆属性
- void Car::show_car()const
- {
-
- if (m_route.empty())
- {
- cout << format("车辆{}未发车!", m_number);
- return;
- }
- cout << format("{:6}{:2}{:6}:{:^7}", "车辆", m_number, "路线", 0);
- for (const Customer* customer : m_route)
- {
- cout << format("{:<4}{:<3}", "->", customer->get_number());
- }
- cout << "-> 0 " << endl;
-
- double start_time{ m_time[0] - Time_Matrix[0][*m_route[0]] };
- double end_time{ m_time.back() + Time_Matrix[*m_route.back()][0] + m_route.back()->get_service_time() };
- cout << format("{:6}{:2}{:6}:{:^9.2f}", "车辆", m_number, "时刻表", start_time);
- for (const auto& time : m_time)
- {
- cout << format("{:^7.2f}", time);
- }
-
- cout << format("{:^7.2f}\n", end_time);
-
- cout << "成本:" << m_cost << endl;
- cout << "载重:" << m_load << endl;
- cout << "行程:" << m_distance_traveled << endl;
- }
-
- // 访问器 //
-
- // 更改器 //
-
-
- // 在路线后添加一个客户
- bool Car::add_customer(const Customer* customer)
- {
- m_route.push_back(customer);
- ++m_customer_number;
- unsigned load{ m_load };
- load += customer->get_requirement();
- if (load > Max_Load)
- {
- // 超重
- m_route.pop_back();
- --m_customer_number;
- return false;
- }
- unsigned distance_traveled{ m_distance_traveled };
- if (m_customer_number < 2)
- {
- distance_traveled += 2 * customer->get_distance(Customer::Distribution_Center);
- }
- else
- {
- distance_traveled -= (*this)[m_customer_number - 2]->get_distance(Customer::Distribution_Center);
- distance_traveled += customer->get_distance((*this)[m_customer_number - 2]);
- distance_traveled += customer->get_distance(Customer::Distribution_Center);
- }
-
- if (distance_traveled > Max_Distance)
- {
- // 超过路程限制
- m_route.pop_back();
- --m_customer_number;
- return false;
- }
- if (!update_time_list())
- {
- // 不符合时间窗限制
- m_route.pop_back();
- --m_customer_number;
- return false;
- }
- // 都满足限制,成功添加一个新客户
- m_load = load;
- m_distance_traveled = distance_traveled;
- return true;
- }
- // 计算配送成本
- void Car::calculate_cost()
- {
- unsigned variable_cost{};
- variable_cost += Variable_Cost * (*this)[0]->get_distance(Customer::Distribution_Center);
- for (int i{}; i < m_route.size() - 1; ++i)
- {
- variable_cost += Variable_Cost * (*this)[i]->get_distance((*this)[i + 1]);
- }
- variable_cost += Variable_Cost * m_route.back()->get_distance(Customer::Distribution_Center);
- m_cost = Fixed_Cost + variable_cost;
- }
- // 更新时刻表
- bool Car::update_time_list()
- {
-
- size_t right_customer_number{ *m_route.back() };
- if (m_customer_number < 2)
- {
- m_time.push_back(Time_Matrix[0][right_customer_number]);
- return true;
- }
- else
- {
- size_t left_customer_number{ *m_route[m_customer_number - 2ull] };
- vector<double> time_array{ m_time }; // 创建一个副本
- double new_time{ time_array[m_customer_number - 2ull] };
- new_time += m_route[m_customer_number - 2ull]->get_service_time() + Time_Matrix[left_customer_number][right_customer_number];
- time_array.push_back(new_time);
- // 检查所有客户的时间窗是否全部满足
- for (int index{}; index < m_customer_number; ++index)
- {
- double time{ time_array[index] };
- double time_difference{ m_route[index]->is_in_window(time) };
- if (time_difference == 1)
- {
- // 无法调整时刻表,时刻表原封不动
- return false;
- }
- else if (time_difference < 0)
- {
- // 尝试调整时刻表
- for (auto& time : time_array)
- {
- time -= time_difference;
- }
- index = -1;
- }
- else
- {
- // 符合此客户的时间约束
- continue;
- }
- }
- // 确定满足条件后,将修改后的副本移动到汽车时刻表中
- m_time = move(time_array);
- return true;
- }
- }
-
-
- // 更改器 //
-
- //展示固有参数,参数为0时,输出矩阵
- void Car::show_parameters(int choice)
- {
- if (choice == 0)
- {
- cout << format("{:26}{:<4}\n{:26}{:<4}\n{:26}{:<4}\n{:26}{:<4}\n{:26}{:<4}\n",
- "车辆最大数量:", Max_Amount,
- "车辆载重量,单位t:", Max_Load,
- "车辆最大行驶距离,单位km:", Max_Distance,
- "车辆固定成本:", Fixed_Cost,
- "车辆单位距离行驶成本:", Variable_Cost);
- cout << format("{:^50}\n", "汽车配送时间矩阵");
- if (Time_Matrix.empty())
- {
- cout << "汽车配送时间矩阵为空!\n";
- }
- else
- {
- for (const auto& row : Time_Matrix)
- {
- for (const auto& time : row)
- {
- cout << format("{:.2f} ", time);
- }
- cout << "\n\n";
- }
- }
- }
- else if (choice == 1)
- {
- cout << format("{:26}{:<4}\n{:26}{:<4}\n{:26}{:<4}\n{:26}{:<4}\n{:26}{:<4}\n",
- "1.车辆最大数量:", Max_Amount,
- "2.车辆载重量,单位t:", Max_Load,
- "3.车辆最大行驶距离,单位km:", Max_Distance,
- "4.车辆固定成本:", Fixed_Cost,
- "5.车辆单位距离行驶成本:", Variable_Cost);
- }
- }
- // Individual.cpp
- #include "Individual.h"
-
- #include<iostream>
- #include<format>
-
- //#define DEBUG
- using
- std::vector,
- std::move,
- std::cout, std::endl,
- std::format;
-
- // 静态成员
-
- vector<Individual> Individual::Best_Individuals{ Individual{} };
-
- // 主构造函数
- Individual::Individual(const vector<int>& dna, unsigned cost, vector<Car> car_array ,unsigned number_of_violations)
- :m_DNA{ dna }, m_fitness{}, m_genetic_probability{}, m_sum_probability{},
- m_cost{ cost }, m_car_array{ car_array } ,m_number_of_violations{ number_of_violations }
- {}
- // 更改器 //
-
-
- // 解码
- void Individual::decode()
- {
- // dna序列转化为客户序列dna_to_customer
- vector<const Customer*> dna_to_customer{};
- for (int gen : m_DNA)
- {
- for (const Customer& customer : Customer::Customer_Array)
- {
- if (static_cast<int>(customer) == gen)
- {
- dna_to_customer.push_back(&customer);
- break;
- }
- }
- }
- // 重置性状为空
- m_car_array.clear();
- m_cost = 0;
- m_number_of_violations = 0;
- // 所有客户添加到汽车序列中
- Car car = Car{ static_cast<unsigned>(m_car_array.size() + 1) };
- for (const auto* customer : dna_to_customer)
- {
- if (car.add_customer(customer))
- {
- // 添加成功,继续添加
- continue;
- }
- else
- {
- // 添加失败,调用新车
- m_car_array.push_back(move(car));
- car = Car{ static_cast<unsigned>(m_car_array.size() + 1) };
- car.add_customer(customer);
- if (m_car_array.size() <= Car::Max_Amount)
- {
- // 调用一辆车后,符合车辆数目约束
- continue;
- }
- else
- {
- // 汽车已用完,施加惩罚,每多调用一辆新车,多一次惩罚
- ++m_number_of_violations;
- }
- }
- }
- m_car_array.push_back(move(car));
- }
-
- // 更新并展示最优解
- void Individual::Update_and_display_solutions()
- {
- update_cost();
- // 更新最优解
- if (m_number_of_violations == Best_Individuals.front().m_number_of_violations)
- {
- if (m_cost < Best_Individuals.front().m_cost)
- {
- // 找到更优解
- Best_Individuals.clear();
- Best_Individuals.push_back(*this);
- Best_Individuals.back().decode();
- Best_Individuals.back().update_cost();
- cout << format("{}\n", "找到更优解:");
- show_individual();
- cout << endl;
- }
- else if (m_cost == Best_Individuals.front().m_cost)
- {
- // 找到另一目标值相同的解
- bool flag{false};
- for (const auto& best_individual : Best_Individuals)
- {
- if (m_DNA == best_individual.get_DNA())
- {
- flag = true;
- break;
- }
- }
- if (!flag)// flag为0,说明这个解和已找到的最优解都不同
- {
- Best_Individuals.push_back(*this);
- Best_Individuals.back().decode();
- Best_Individuals.back().update_cost();
- cout << format("{}\n", "找到另一更优解:");
- show_individual();
- cout << endl;
- }
- }
- }
- else if (m_number_of_violations < Best_Individuals.front().m_number_of_violations)
- {
- // 找到更优解
- Best_Individuals.clear();
- Best_Individuals.push_back(*this);
- Best_Individuals.back().decode();
- Best_Individuals.back().update_cost();
- cout << format("{}\n", "找到更优解:");
- show_individual();
- cout << endl;
- }
- }
- // 计算成本
- unsigned Individual::update_cost()
- {
- for (Car& car : m_car_array)
- {
- car.calculate_cost();
- m_cost += car.get_cost();
-
- }
- return m_cost;
- }
- // 展示个体
- void Individual::show_individual()const
- {
- cout << format("\n{:-^80}\n{:*^80}\n", "", "");
- for (const Car& car : m_car_array)
- {
- car.show_car();
- cout << endl;
- }
- cout << format("{}:{}\n", "总成本", m_cost);
- if (m_number_of_violations > 0)
- {
- // 违反了约束
- cout << format("{}:{}\n", "违反约束次数", m_number_of_violations);
- }
- else
- {
- cout << format("{}\n{:*^80}\n{:-^80}\n", "符合约束", "", "");
- }
- }
-
- // 更改器 //
- // Genetic_Algorithm.cpp
- #include "Genetic_Algorithm.h"
-
- #include<format>
- #include<iostream>
- #include<random>
- #include<functional>
-
- //#define DEBUG
- using
- std::vector, std::array,
- std::format,
- std::cout, std::endl,
- std::move;
-
- Individual Genetic_Algorithm::Best_Individual_in_History{ vector<int>{1, 6, 10, 5, 2, 9, 7, 8, 4, 3} };
-
- // 类外函数 //
-
- // 生成伪随机正整数,左闭右闭区间
- unsigned Pseudo_random_number(unsigned min, unsigned max)
- {
- using std::random_device, std::default_random_engine, std::uniform_int_distribution;
- random_device seeder; // 真随机数作为种子
- default_random_engine generator{ seeder() }; // 伪随机数生成器
- uniform_int_distribution<unsigned> distribution{ min,max }; // 整数均匀分布
- return distribution(generator);
- }
- // 伪随机数生成器PRNG,正整数类,左闭右闭区间
- auto create_pseudo_random_number_generator(unsigned min, unsigned max)
- {
- using std::random_device, std::default_random_engine, std::uniform_int_distribution, std::bind;
- random_device seeder; // 真随机数作为种子
- default_random_engine generator{ seeder() }; // 伪随机数生成器
- uniform_int_distribution<unsigned> distribution{ min,max }; // 整数均匀分布
- return bind(distribution, generator);
- }
- // 生成伪随机实数,左闭右开区间
- double Pseudo_random_number(double min, double max)
- {
- using std::random_device, std::default_random_engine, std::uniform_real_distribution;
- random_device seeder; // 真随机数作为种子
- default_random_engine generator{ seeder() }; // 伪随机数生成器
- uniform_real_distribution<double> distribution{ min,max }; // 实数均匀分布
- return distribution(generator);
- }
- // 伪随机数生成器PRNG,实数类,左闭右开区间
- auto create_pseudo_random_number_generator(double min, double max)
- {
- using std::random_device, std::default_random_engine, std::uniform_real_distribution, std::bind;
- random_device seeder; // 真随机数作为种子
- default_random_engine generator{ seeder() }; // 伪随机数生成器
- uniform_real_distribution<double> distribution{ min,max }; // 实数均匀分布
- return bind(distribution, generator);
- }
-
- // 函数模板,实现交换两个基本类型的值
- template<typename T>
- void swap(T& left, T& right)
- {
- T temp{ left };
- left = move(right);
- right = move(temp);
- }
-
-
- // 初始化种群
- void Genetic_Algorithm::initialize()
- {
- Mutation_P = 1.0 / 1024;
- m_population.reserve(Po_Size);
- for (size_t i{}; i < Po_Size; ++i)
- {
- vector<int>dna{};
- dna.reserve(Customer::Size - 1ull);
- for (int gen{ 1 }; gen < Customer::Size; ++gen)
- {
- dna.push_back(gen);
- }
- auto random_index{ create_pseudo_random_number_generator(0u,Customer::Size - 2u) };
- for (int times{}; times < Customer::Size; ++times)
- {
- swap(dna[random_index()], dna[random_index()]);
- }
- m_population.push_back(Individual{ dna });
- }
- }
- // 获得适应度
- void Genetic_Algorithm::get_fitness()
- {
- for (Individual& individual:m_population)
- {
- individual.decode();
- individual.Update_and_display_solutions();
- individual.update_fitness();
- if (individual.get_number_of_violations() > 0)
- {
- unsigned punish_times{ individual.get_number_of_violations() };
- individual.multiply_fitness(Punish, punish_times);
- }
- }
- }
- // 获得遗传概率
- void Genetic_Algorithm::get_genetic_probability()
- {
- double sum{};
- for (const Individual& individual : m_population)
- {
- sum += individual.get_fitness();
- }
- for (Individual& individual : m_population)
- {
- individual.set_genetic_probability(individual.get_fitness() / sum);
- }
- }
- // 获得轮盘赌累加概率
- void Genetic_Algorithm::get_sum_probability()
- {
- for (double sum{}; Individual& individual : m_population)
- {
- sum += individual.get_genetic_probability();
- individual.set_sum_probability(sum);
- }
- m_population.back().set_sum_probability(1.0); // 最后一个体,轮盘赌值为1,消除double类型的误差
- }
-
-
- // 遗传算子 //
-
- // 选择算子,轮盘赌多选法
- void Genetic_Algorithm::selection()
- {
- vector<unsigned> son_number(Po_Size,0); // 索引对应的子代数量
- static auto random{ create_pseudo_random_number_generator(0.0,1.0) };
- double point{ random() };
- const double add_number{ 1.0 / Po_Size };
- for (size_t times{}, next_index{}; times < Po_Size; ++times)
- {
- for (size_t index{ next_index }; index < Po_Size; ++index)
- {
- if (point < m_population[index].get_sum_probability())
- {
- next_index = index;
- ++son_number[index];
- point += add_number;
- if (point > 1.0)
- {
- --point;
- next_index = 0;
- }
- break;
- }
- }
- }
- vector<Individual> son_population{};
- son_population.reserve(Po_Size);
- for (size_t index{}; index < Po_Size; ++index)
- {
- for (unsigned times{}; times < son_number[index]; ++times)
- {
- son_population.push_back(m_population[index]);
- }
- }
- m_population = move(son_population);
- }
- // 交叉算子,两点交叉+映射法
- void Genetic_Algorithm::crossover()
- {
- using std::pair, std::make_pair;
- // spouse:配偶,夫妻
- auto random_spouse_index{ create_pseudo_random_number_generator(0u, static_cast<unsigned>(Po_Size) - 1u) };
- auto random_cross_point_index{ create_pseudo_random_number_generator(0u, Customer::Size - 2u) };
- for (size_t spouse{}; spouse < Po_Size / 2; ++spouse)
- {
- if (Pseudo_random_number(0, 1.0) < Crossover_P)
- {
- // 开始交叉
- Individual& father{ m_population[random_spouse_index()] };
- Individual& mother{ m_population[random_spouse_index()] };
- // 交叉点位置
- size_t cross_point_left{ random_cross_point_index() };
- size_t cross_point_right{ random_cross_point_index() };
- if (cross_point_left > cross_point_right) { swap(cross_point_left, cross_point_right); }
- vector<pair<int, int>> Map_from_father_to_mother{};
- Map_from_father_to_mother.reserve(cross_point_right - cross_point_left + 1);
- // 交换基因
- for (size_t cross_point{ cross_point_left }; cross_point <= cross_point_right; ++cross_point)
- {
- int& father_gen{ father[cross_point] };
- int& mother_gen{ mother[cross_point] };
- Map_from_father_to_mother.push_back(make_pair(father_gen, mother_gen));
- swap(father_gen, mother_gen);
- }
- // 映射
- for (const pair<int,int>& map : Map_from_father_to_mother)
- {
- for (int& gen : father.set_DNA())
- {
- if (int switch_gen{ map.first }; gen == map.second)
- {
- swap(gen, switch_gen);
- break;
- }
- }
- for (int& gen : mother.set_DNA())
- {
- if (int switch_gen{ map.second }; gen == map.first)
- {
- swap(gen, switch_gen);
- break;
- }
- }
- }
- }
- }
- }
- // 变异算子,两点交换变异
- void Genetic_Algorithm::mutation()
- {
- static auto random{ create_pseudo_random_number_generator(0.0, 1.0) };
- auto random_exchange_point{ create_pseudo_random_number_generator(0u, Customer::Size - 2u) };
- for (auto& individual : m_population)
- {
- if (random() < Mutation_P)
- {
- // 开始变异
- swap(individual[random_exchange_point()], individual[random_exchange_point()]);
- }
- }
- }
- // 遗传算子 //
-
- // 遗传算法入口
- void Genetic_Algorithm::genetic_algorithm()
- {
- // 初始化种群
- initialize();
- for (size_t generation{}; generation <= Iterations; ++generation)
- {
- if (generation % 10ull == 0)
- {
- cout << format("{:->50}{:^5}{:-<50}\n", "第", generation, "代");
- }
- // 获得适应度
- get_fitness();
- // 获得遗传概率
- get_genetic_probability();
- // 获得轮盘赌累加概率
- get_sum_probability();
-
- // 遗传算子 //
-
- // 选择算子,轮盘赌多选法
- selection();
- // 交叉算子,两点交叉+映射法
- crossover();
- // 变异算子,两点交换变异
- mutation();
-
- // 遗传算子 //
-
- // 遗传概率调整
- if ((generation + 1) % 128ull == 0)
- {
- static auto random_0_to_1{ create_pseudo_random_number_generator(0.0,1.0) };
- Crossover_P = random_0_to_1();
- static const double mutation_probability_Increase{ (1.0 - Mutation_P) / Iterations * 64 };
- Mutation_P += mutation_probability_Increase;
- cout << "交叉概率:" << Crossover_P
- << "\n变异概率:" << Mutation_P << "\n";
- }
- }
- get_fitness();
- Best_Individual_in_History.decode();
- Best_Individual_in_History.update_cost();
- if (Individual::Best_Individuals.size() == 1)
- {
- cout << "\n找到唯一最优解:\n";
- Individual::Best_Individuals.front().show_individual();
- if (Individual::Best_Individuals.front().get_DNA() == Best_Individual_in_History.get_DNA())
- {
- cout << "\n本次最优解与历史最优解目标值相同!\n";
- }
- else
- {
- cout << "\n历史最优解:\n";
- Best_Individual_in_History.show_individual();
- }
- }
- else if (Individual::Best_Individuals.size() > 1)
- {
- cout << "\n找到多个最优解:\n";
- for (const auto& best_individual : Individual::Best_Individuals)
- {
- best_individual.show_individual();
- }
- if (Individual::Best_Individuals.front().get_cost() == Best_Individual_in_History.get_cost())
- {
- cout << "\n本次最优解与历史最优解目标值相同!\n";
- }
- else
- {
- cout << "\n历史最优解:\n";
- Best_Individual_in_History.show_individual();
- }
- }
- }
-
- // 展示固有参数
- void Genetic_Algorithm::show_parameters(int choice)
- {
- if (choice == 0)
- {
- cout << format("{:12}{:^6}\n{:12}{:^6}\n{:12}{:^6}\n{:12}{:^6}\n{:12}{:^6}\n",
- "种群规模:", Po_Size,
- "进化代数:", Iterations,
- "交叉概率:", Crossover_P,
- "变异概率:", Mutation_P,
- "惩罚系数:", Punish);
- }
- else if (choice == 1)
- {
- cout << format("{:12}{:^6}\n{:12}{:^6}\n{:12}{:^6}\n{:12}{:^6}\n",
- "6.种群规模:", Po_Size,
- "7.进化代数:", Iterations,
- "8.交叉概率:", Crossover_P,
- "9.变异概率:", Mutation_P);
- }
- }
- //UI_Manage.cpp
- #include "UI_Manage.h"
-
-
- #include<iostream>
- #include<format>
- #include<fstream>
- #include<Windows.h>
-
- using
- std::string_view, std::string,
- std::cout, std::endl,
- std::format;
-
-
-
- // 展示菜单
- void UI_Manage::Show_Menu()const
- {
- cout << format("{:*^30}\n{:*^30}\n{:*^30}\n{:*^30}\n{:*^30}\n{:*^30}\n{:*^30}\n{:*^30}\n{:*^30}\n",
- ""
- ," 遗传算法v1.0 "
- ," by : 雷海泷 "
- ,"0. 退出 "
- ,"1. 读取文件 "
- ,"2. 展示参数 "
- ,"3.展示文件路径"
- ,"4. 开始求解 "
- ,"5. 修改参数 "
- ,"");
- }
-
- // 读取文件1
- bool UI_Manage::read_file(string_view distance_file, string_view time_file, string_view customer_file)
- {
- using std::ifstream, std::ios, std::vector, std::array, std::move;
- ifstream distance_ifs{ string{distance_file},ios::in };
- ifstream time_ifs{ string{time_file},ios::in };
- ifstream customer_ifs{ string{customer_file},ios::in };
- char buf[100]{};
- GetCurrentDirectoryA(100, buf);
- if (!distance_ifs.is_open())
- {
- cout << format("文件{}\\{}打开失败!\n", buf, distance_file);
- time_ifs.close();
- customer_ifs.close();
- return false;
- }
- else if (!time_ifs.is_open())
- {
- cout << format("文件{}\\{}打开失败!\n", buf, time_file);
- distance_ifs.close();
- customer_ifs.close();
- return false;
-
- }
- else if (!customer_ifs.is_open())
- {
- cout << format("文件{}\\{}打开失败!\n", buf, customer_file);
- distance_ifs.close();
- time_ifs.close();
- return false;
- }
- else
- {
- Customer::Distance_Matrix.clear();
- Car::Time_Matrix.clear();
- Customer::Customer_Array.clear();
- Customer::Customer_Array.push_back(move(Customer{}));
- unsigned number, requirement, time_start1, time_end1, time_start2, time_end2;
- double service_time;
- while (customer_ifs >> number
- && customer_ifs >> requirement
- && customer_ifs >> service_time
- && customer_ifs >> time_start1
- && customer_ifs >> time_end1
- && customer_ifs >> time_start2
- && customer_ifs >> time_end2)
- {
- Customer::Customer_Array.push_back(move(Customer{ number,requirement,service_time, array<Time, Window_num> { Time{ time_start1, time_end1 }, Time{ time_start2, time_end2 } } }));
- }
- Customer::Size = static_cast<int>(Customer::Customer_Array.size());
- cout << format("文件{}\\{}读取成功!\n", buf, customer_file);
- customer_ifs.close();
- for (size_t i{}; i < Customer::Size; ++i)
- {
- vector<int> distance_row{};
- int distance;
- for (size_t j{}; j < Customer::Size && distance_ifs >> distance; ++j)
- {
- distance_row.push_back(distance);
- }
- Customer::Distance_Matrix.push_back(move(distance_row));
- vector<double> time_row{};
- double time;
- for (size_t j{}; j < Customer::Size && time_ifs >> time; ++j)
- {
- time_row.push_back(time);
- }
- Car::Time_Matrix.push_back(move(time_row));
- }
- cout << format("文件{}\\{}读取成功!\n", buf, distance_file);
- distance_ifs.close();
- cout << format("文件{}\\{}读取成功!\n", buf, time_file);
- time_ifs.close();
- m_file_read = true;
- return true;
- }
- }
- // 展示所有参数2
- void UI_Manage::show_all_parameters()const
- {
- if (!m_file_read)
- {
- cout << "未读取文件!\n";
- system("pause");
- }
- else
- {
- // Customer
- cout << format("{:-^30}\n", "客户与配送中心参数");
- Customer::show_parameters();
- // Car
- cout << format("{:-^30}\n", "车辆参数");
- Car::show_parameters();
-
- // Genetic_Algorithm
- cout << format("{:-^30}\n", "遗传算法参数");
- Genetic_Algorithm::show_parameters();
- }
-
- }
-
- // 展示文件路径3
- void UI_Manage::show_file_path()const
- {
- char buf[100]{};
- GetCurrentDirectoryA(100, buf);
- cout << format("{}:{}\\\n", "当前路径", buf);
- }
-
- // 开始求解4
- void UI_Manage::start_solve(string_view distance_file, string_view time_file, string_view customer_file)
- {
- if (!m_file_read)
- {
- cout << "未读取文件!\n";
- system("pause");
- return;
- }
- read_file(distance_file, time_file, customer_file);
- Genetic_Algorithm GA{};
- LARGE_INTEGER start_time, end_time, frequency;
- QueryPerformanceFrequency(&frequency);
- QueryPerformanceCounter(&start_time);
-
- GA.genetic_algorithm();
-
- QueryPerformanceCounter(&end_time);
- long long run_time{ (end_time.QuadPart - start_time.QuadPart) * 1'000 / frequency.QuadPart };
- long long minute{run_time / 60'000 };
- long long second{ (run_time - minute * 60'000) / 1'000 };
- long long millisecond{ run_time - minute * 60'000 - second * 1'000 };
- cout << format("{}{}{}{}{}{}{}\n", "用时 ", minute, "分", second, "秒", millisecond, "毫秒");
- }
-
- // 修改参数5
- void UI_Manage::modify_parameters()
- {
- using std::cin;
- if (!m_file_read)
- {
- cout << "未读取文件!\n";
- system("pause");
- return;
- }
- int choice{ -1 };
- while (true)
- {
- cout << "可修改的参数:\n";
- cout << format("{:}\n", "0.退出");
- Car::show_parameters(1);
- Genetic_Algorithm::show_parameters(1);
- cout << "请输入您的选择:" << endl;
- cin >> choice;
- //输入检查
- if (cin.fail())
- {
- cout << "输入错误!" << endl;
- cin.clear();
- cin.ignore(1024, '\n');
- system("pause");
- continue;
- }
- switch (choice)
- {
- case 0:// 退出
- return;
- case 1:// 1.车辆最大数量
- {
- unsigned input_value{ Car::Max_Amount };
- cout << "修改为:";
- cin >> input_value;
- //输入检查
- if (cin.fail())
- {
- cout << "输入错误!" << endl;
- cin.clear();
- cin.ignore(1024, '\n');
- system("pause");
- continue;
- }
- Car::Max_Amount = input_value;
- break;
- }
-
- case 2:// 2.车辆载重量
- {
- unsigned input_value{ Car::Max_Load };
- cout << "修改为:";
- cin >> input_value;
- //输入检查
- if (cin.fail())
- {
- cout << "输入错误!" << endl;
- cin.clear();
- cin.ignore(1024, '\n');
- system("pause");
- continue;
- }
- Car::Max_Load = input_value;
- break;
- }
- case 3:// 3.车辆最大行驶距离
- {
- unsigned input_value{ Car::Max_Distance };
- cout << "修改为:";
- cin >> input_value;
- //输入检查
- if (cin.fail())
- {
- cout << "输入错误!" << endl;
- cin.clear();
- cin.ignore(1024, '\n');
- system("pause");
- continue;
- }
- Car::Max_Distance = input_value;
- break;
- }
- case 4:// 4.车辆固定成本
- {
- unsigned input_value{ Car::Fixed_Cost };
- cout << "修改为:";
- cin >> input_value;
- //输入检查
- if (cin.fail())
- {
- cout << "输入错误!" << endl;
- cin.clear();
- cin.ignore(1024, '\n');
- system("pause");
- continue;
- }
- Car::Fixed_Cost = input_value;
- break;
- }
- case 5:// 5.车辆单位距离行驶成本
- {
- unsigned input_value{ Car::Variable_Cost };
- cout << "修改为:";
- cin >> input_value;
- //输入检查
- if (cin.fail())
- {
- cout << "输入错误!" << endl;
- cin.clear();
- cin.ignore(1024, '\n');
- system("pause");
- continue;
- }
- Car::Variable_Cost = input_value;
- break;
- }
- case 6:// 6.种群规模
- {
- size_t input_value{ Genetic_Algorithm::Po_Size };
- cout << "修改为:";
- cin >> input_value;
- //输入检查
- if (cin.fail())
- {
- cout << "输入错误!" << endl;
- cin.clear();
- cin.ignore(1024, '\n');
- system("pause");
- continue;
- }
- Genetic_Algorithm::Po_Size = input_value;
- break;
- }
- case 7:// 7.进化代数
- {
- size_t input_value{ Genetic_Algorithm::Iterations };
- cout << "修改为:";
- cin >> input_value;
- //输入检查
- if (cin.fail())
- {
- cout << "输入错误!" << endl;
- cin.clear();
- cin.ignore(1024, '\n');
- system("pause");
- continue;
- }
- Genetic_Algorithm::Iterations = input_value;
- break;
- }
- case 8:// 8.交叉概率
- {
- double input_value{ Genetic_Algorithm::Crossover_P };
- cout << "修改为:";
- cin >> input_value;
- //输入检查
- if (cin.fail())
- {
- cout << "输入错误!" << endl;
- cin.clear();
- cin.ignore(1024, '\n');
- system("pause");
- continue;
- }
- Genetic_Algorithm::Crossover_P = input_value;
- break;
- }
- case 9:// 9.变异概率
- {
- double input_value{ Genetic_Algorithm::Mutation_P };
- cout << "修改为:";
- cin >> input_value;
- //输入检查
- if (cin.fail())
- {
- cout << "输入错误!" << endl;
- cin.clear();
- cin.ignore(1024, '\n');
- system("pause");
- continue;
- }
- Genetic_Algorithm::Mutation_P = input_value;
- break;
- }
- default://输入错误
- cout << "输入错误!" << endl;
- system("pause");
- break;
- }
- system("cls");
- }
- }
- // 遗传算法v1.0.cpp
- #include<iostream>
- #include<format>
- #include<Windows.h>
-
- #include"UI_Manage.h"
-
- using
- std::cout, std::cin,std::endl,
- std::format,
- std::vector, std::array;
-
-
-
-
-
-
- int main()
- {
- try
- {
- UI_Manage ui;
- int choice{ -1 };
- while (true)
- {
- ui.Show_Menu();
- cout << "请输入您的选择:" << endl;
- cin >> choice;
- //输入检查
- if (cin.fail())
- {
- cout << "输入错误!即将返回菜单!" << endl;
- cin.clear();
- cin.ignore(1024, '\n');
- system("pause");
- continue;
- }
-
- switch (choice)
- {
- case 0:// 退出程序
- ui.exit_system();
- break;
- case 1:// 读取文件
- ui.read_file();
- system("pause");
- break;
- case 2:// 展示所有参数
- ui.show_all_parameters();
- system("pause");
- break;
- case 3:// 展示当前路径
- ui.show_file_path();
- system("pause");
- break;
- case 4:// 开始求解
- ui.start_solve();
- system("pause");
- break;
- case 5:// 修改参数
- ui.modify_parameters();
- break;
- default:// 输入错误
- cout << "输入错误!即将返回菜单!" << endl;
- system("pause");
- break;
- }
- system("cls");
- }
- return 0;
- }
- catch (const std::exception& trouble)
- {
- cout << "发生异常:" << trouble.what() << endl;
- system("pause");
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。