GA(C++代码实现)——背包问题
引用博客:https://www.cnblogs.com/suchang/p/10550181.html
本文是在上面那篇博客的基础上用遗传算法解决背包问题,并用C++加以实现。
遗传算法的具体讲解因为时间有限,暂时不加解释,网上也有很多,大家也可以看看上面那篇博客。
然后我就只展示一下代码。因为我还只是个C++小白,如果大家有什么问题可以在评论区讨论交流,谢谢大家。
主函数
#include"GA.h"
using namespace std;
int main()
{
genetic_algorithm();
system("pause");
}
头文件
#pragma once
#include<iostream>
#include<string>
#include<vector>
#include<fstream>
#include<regex>
#include<random>
#include<iomanip>
using namespace std;
const int NP = 100; //种群规模
const int L = 10; //物品件数
const double Pc = 0.8;//交叉率
const double Pm = 0.05;//变异率
const int G = 1000; //最大遗传代数
const int V = 300; //背包容量
const int afa = 2; //惩罚函数系数
class Individual //定义个体类
{
private:
bool gene[L];//基因值
double fitness;//适应值
double Rfitness;//适应值概率
double Sumfitness;//累加概率
public:
Individual();
Individual(bool* m_Variable);//默认构造函数
//Individual(double* m_Variable);//构造函数
bool* Getgene();//获取变量值
void Chafitness(const double m_fitness);//修改适应值
void ChaRfitness(const double m_ReFitness);//修改适应值概率
void ChaSumfitness(const double m_SumFitness);//修改累加概率
double Getfitness()const;//获取适应值
double GetRfitness()const;//获取适应值概率
double GetSumfitness()const;//获取累加概率
~Individual(); //析构函数
};
void input();//读取文件
void Initialize();//随机初始化种群,得到第一代个体
void CaculaFitness();//计算个体的适应值
void CaculaReFitness();//计算个体的适应值概率
void CalculaSumFitness();//计算累加个体概率
void seclect();//种群选择
double Scand();//随机产生0到49的随机整数
void crossing();//杂交
void variating();//变异
void genetic_algorithm();//遗传算法
我之所以加了一个读取文件的一个函数,是因为我觉得大家有些数据很庞大,可能是.data,.txt这样的文件,如果不需要读文件的同学最好也把自己的 数据存到一个.txt文件中来运行,否则改动会很大。
GA.cpp
#include"GA.h"
vector<vector<int>> C; //存放物品体积和价值
vector<int> temp_line;
string line;
vector<Individual> nowpopulation;//P(t)种群
vector<Individual> midpopulation;//中间种群,存放轮盘选择后的优秀个体
vector<Individual> nextpopulation;//P(t+1)种群
Individual::Individual()
{
}
Individual::Individual(bool* m_Variable)
{
//初始化时默认适应值等值为0
for (int i = 0; i < L; i++)
{
gene[i] = m_Variable[i];
}
this->fitness = 0;
this->Rfitness = 0;
this->Sumfitness = 0;
}
bool* Individual::Getgene()//获取基因值
{
return gene;
}
double Individual::Getfitness()const//获取适应值
{
return fitness;
}
double Individual::GetRfitness()const //获取适应值概率
{
return Rfitness;
}
double Individual::GetSumfitness()const//获取累加概率
{
return Sumfitness;
}
void Individual::Chafitness(const double m_fitness)//修改适应值
{
this->fitness = m_fitness;
}
void Individual::ChaRfitness(const double m_ReFitness)//修改适应值概率
{
this->Rfitness = m_ReFitness;
}
void Individual::ChaSumfitness(const double m_SumFitness)//修改累加概率
{
this->Sumfitness = m_SumFitness;
}
Individual::~Individual()
{
}
//读取文件
void input()
{
ifstream in("package.txt"); //读入文件
regex pat_regex("[[:digit:]]+"); //匹配原则,这里代表一个或多个数字
while (getline(in, line))
{ //按行读取
for (sregex_iterator it(line.begin(), line.end(), pat_regex), end_it; it != end_it; ++it) { //表达式匹配,匹配一行中所有满足条件的字符
cout << it->str() << " "; //输出匹配成功的数据
temp_line.push_back(stoi(it->str())); //将数据转化为int型并存入一维vector中
}
cout << endl;
C.push_back(temp_line); //保存所有数据
temp_line.clear();
}
}
//随机初始化种群,得到第一代个体
void Initialize()
{
bool X1[NP][L];//使用矩阵保存随机数的变量值
for (int i = 0; i < NP; i++)
{
bool tempL[L];
for (int j = 0; j < L; j++)
{
X1[i][j] = rand() % 2;
tempL[j] = X1[i][j];
//cout << tempL[j] << " ";
}
//cout << endl;
Individual V1(tempL);//通过有参构造函数输入类中,形成一个染色体
nowpopulation.push_back(V1);
}
}
//计算个体的适应值
void CaculaFitness()
{
int X2[L];
for (int i = 0; i < NP; i++)
{
double tempF = 0;
double Totalsize = 0;
for (int j = 0; j < L; j++)
{
X2[j] = nowpopulation.at(i).Getgene()[j];
tempF += X2[j]*C[1][j];
Totalsize += X2[j] * C[0][j];
}
if (Totalsize <= V)
{
nowpopulation.at(i).Chafitness(tempF);
}
else
{
tempF = tempF - afa * (Totalsize - V);
}
nowpopulation.at(i).Chafitness(tempF);
}
}
//计算个体的适应值概率
void CaculaReFitness()
{
double tempsum = 0;//适应值累加器
double tempf = 0;
for (int i = 0; i < NP; i++)//计算出适应值之和
{
tempsum += nowpopulation.at(i).Getfitness();
}
for (int j = 0; j < L; j++)
{
tempf = nowpopulation.at(j).Getfitness() / tempsum;//计算概率
nowpopulation.at(j).ChaRfitness(tempf);//修改个体的适应度概率
}
}
//计算累加个体概率
void CalculaSumFitness()
{
double summation = 0;//累加器
for (int k = 0; k < NP; k++)
{
summation += nowpopulation.at(k).GetRfitness();
nowpopulation.at(k).ChaSumfitness(summation);//当前累加结果赋值
}
}
//种群选择
void seclect()
{
//随机生生成0到1的小数
double array[NP];//随机数保存变量
default_random_engine e(time(0));//引擎,生成随机序列,#include<random>
uniform_real_distribution<double> u(0.0, 1.0); //分布 #include<random>
for (int i = 0; i < NP; i++)
array[i] = u(e);
for (int i = 0; i < NP; i++)
{
for (int j = 1; j < NP; j++)
{
if (array[i] < nowpopulation[j - 1].GetSumfitness())
{
midpopulation.push_back(nowpopulation.at(j - 1));//加入中间种群
}
if (array[i] >= nowpopulation.at(j - 1).GetSumfitness() && array[i] <= nowpopulation.at(j).GetSumfitness())
{
midpopulation.push_back(nowpopulation.at(j));//加入中间种群
}
}
}
nowpopulation.clear();//清空nowpopulation
}
随机产生0到1的数
double Scand()
{
int N = rand() % 999;
return double(N) / 1000.0;;//随机产生0到1的小数
}
//杂交
void crossing()
{
int num = 0;//记录次数
double corss = 0.0;//保存随机产生的概率值
srand((unsigned)time(NULL));//根据系统时间设置随机数种子,设置一次随机种子就行
bool array1[L], array2[L];//临时存储父亲和母亲的变量值
while (num < NP - 1)
{
corss = Scand();
if (corss < Pc)
{
bool tempL[L]; //生成一个随机的基因
bool tempc; //随机的点
for (int i = 0; i < L; i++)
{
tempL[i] = rand() % 2;
}
for (int i = 0; i < L; i++)
{
array1[i] = midpopulation.at(num).Getgene()[i]; //父亲的自变量
array2[i] = midpopulation.at(num + 1).Getgene()[i]; //母亲自变量
}
for (int j = 0; j < L; j++)
{
if (tempL[j]==1) //进行单点交叉
{
tempc = array2[j];
array2[j] = array1[j];
array1[j] = tempc;
}
}
Individual V2(array1);
Individual V3(array2);
nextpopulation.push_back(V2);
nextpopulation.push_back(V3);
}
else//否则直接遗传给下一代nextpopulation
{
nextpopulation.push_back(midpopulation.at(num));//生成一个新的个体并且加入到nextpopulation中
nextpopulation.push_back(midpopulation.at(num + 1));
}
num += 2;
}
midpopulation.clear();//清空midpopulation
}
//变异
void variating()
{
int num = 0;
while (num < NP)
{
bool array3[L];
for (int i = 0; i < L; i++)
{
array3[i] = nextpopulation.at(num).Getgene()[i];
}
for (int j = 0; j < L; j++)
{
double vari = Scand();
if (vari < Pm)
{
if (array3[j])
{
array3[j] == 0;
}
else
{
array3[j] == 1;
}
}
}
Individual V4(array3);
nowpopulation.push_back(V4);
num++;
}
}
//测试函数
void test01(int k)
{
cout << setw(10) << "属性值" << setw(20) << "Fitness" << endl;
for (int i = 0; i < NP; i++)
{
for (int j = 0; j < L; j++)
{
cout << nowpopulation.at(i).Getgene()[j] << " ";
}
cout <<setw(8)<< nowpopulation.at(i).Getfitness() << " " << endl;
}
cout << "最优策略:";
for (int j = 0; j < L; j++)
{
cout << nowpopulation.at(k).Getgene()[j] << " ";
}
cout << endl;
cout << "maxFitness:" << nowpopulation.at(k).Getfitness() << endl;
}
//遗传算法
void genetic_algorithm()
{
input();
Initialize();//初始化种群,随机生成第一代个体
//进化500代
for (int i = 0; i < G; i++)
{
CaculaFitness();//适应度计算
CaculaReFitness();//适应度概率计算
CalculaSumFitness();//计算累加个体概率
seclect();//选择
crossing();//杂交
variating();//变异
}
CaculaFitness();//适应度计算
double maxfitness = nowpopulation.at(0).Getfitness();
int maxid = 0;
int k;
for (k = 0; k < NP; k++)
{
if (maxfitness < nowpopulation.at(k).Getfitness())
{
maxfitness = nowpopulation.at(k).Getfitness();
maxid = k;
}
}
test01(maxid);
}