#include<iostream>
#include<iomanip>
#include<algorithm>
#include<cmath>
#include<ctime>
using namespace std;
//程序分配内存的数组大小
const int maxn = 10000;//最大种群规模
const int maxlen = 1000;//最大的染色体长度
//遗传算法的关键参数
const int n = 200;//种群的个体数
const int len = 30;//每个个体染色体的长度,x和y各占据一半
const int crossNum = 4;//交叉操作时多点交叉的交叉点个数
const int maxGeneration = 2000;//最大进化代数
const double probCross = 0.85;//交叉概率
const double proMutation = 0.15;//编译概率
//个体的染色体类
class Chromosome {
public:
bool g[maxlen];//二进制的编码数组
Chromosome() {//默认构造函数
for(int i = 0 ; i < len ; i ++) {
g[i] = rand() % 2;
}
}
Chromosome(const Chromosome& c) {//拷贝构造函数,进行深复制
for(int i = 0 ; i < len ; i ++) {
g[i] = c.g[i];
}
}
void operator=(const Chromosome& c) {//重载=号,进行深复制
for(int i = 0 ; i < len ; i ++) {
g[i] = c.g[i];
}
}
};
double bestValue;//记录当前所得的最优值
Chromosome bestC;//记录当前最优值对应的个体染色体
Chromosome group[maxn], temGroup[maxn];//个体的种群,辅助数组
//目标函数
double f(double x, double y) {
return x * sin(10 * M_PI * x) + 2.0;
}
//解码函数,从染色体得到x和y的值
void decode(const Chromosome& c, double& x, double& y) {
double num = pow(2.0, len / 2.0);
int tem = 0;
for(int i = len-1 ,q = 1 ; i >= len/2 ; i --) {
tem += c.g[i] * q;
q *= 2;
}
y = 1 + (2 - 1) / num * tem;
tem = 0;
for(int i = len/2 - 1, q = 1 ; i >= 0 ; i --) {
tem += c.g[i] * q;
q *= 2;
}
x = 1 + (2 - 1) / num * tem;
}
//适应度函数,为了避免负值,把目标函数添加一个正数
double fitness(const Chromosome& c) {
double x, y;
decode(c, x, y);
return f(x, y) + 5;
}
//辅助函数,生成0-1之间的随机小数
double inline random_0_1() {
return rand() % 10000 / 10000.0;
}
//选择操作
void select(Chromosome group[maxn]) {
//计算每个个体的选择概率
double fitnessValue[maxn];
for(int i = 0 ; i < n ; i ++) {
fitnessValue[i] = fitness(group[i]);
}
double sum = 0;
for(int i = 0 ; i < n ; i ++) {
sum += fitnessValue[i];
}
double prob[maxn];
for(int i = 0 ; i < n ; i ++) {
prob[i] += fitnessValue[i];
}
//随机选择n个个体组成新种群
int selectId[maxn];
for(int i = 0 ; i < n ; i ++) {
prob[i] += prob[i-1];
}
for(int i = 0 ; i < n ; i ++) {
//使用轮盘算法选择个体
double randNum = random_0_1();
int j;
for(j = 0 ; j < n-1 ; j ++) {
if(randNum < prob[j]) {
selectId[i] = j;
break;
}
}
if(j == n-1) {
selectId[i] = j;
}
}
//把种群更新为新选择的个体集合
for(int i = 0 ; i < n ; i ++) {
temGroup[i] = group[i];
}
for(int i = 0 ; i < n ; i ++) {
group[i] = temGroup[selectId[i]];
}
}
//交叉操作,使用多点交叉
void crossOver(Chromosome& c1, Chromosome& c2) {
//生成交叉位置,并排序
int crossPoint[maxn];
for(int i = 0 ; i < crossNum; i ++) {
crossPoint[i] = rand() % len;
}
sort(crossPoint, crossPoint + crossNum);
//进行交叉
bool flag = 0;
for(int i = 0, j = 0 ; i < len ; i ++) {
if(!flag) {
swap(c1.g[i], c2.g[i]);
}
if(i == crossPoint[j]) {
//如果若干个交叉点重合,则效果叠加
//偶数个交叉点效果相当于没有交叉点
while(j < crossNum && i == crossPoint[j]) {
j ++;
flag = !flag;
}
}
}
}
//变异操作
void mutate(Chromosome& c) {
//随机选择一位进行翻转
int i = rand() % len;
c.g[i] = !c.g[i];
}
//获取种群最优个体
int getOptimal(Chromosome group[maxn], double& x, double& y, double& value) {
//计算适应值,遍历得到最优值并进行解码
double fitnessValue[maxn];
int id = 0;
for(int i = 0 ; i < n ; i ++) {
if(fitnessValue[i] > fitnessValue[id]) {
id = i;
}
}
decode(group[id], x, y);
value = f(x, y);
return id;
}
//遗传算法总代码
void GA(double& x, double& y, double& value) {
//初始化种群
for(int i = 0 ; i < n ; i ++) {
group[i] = Chromosome();
}
bestC = group[getOptimal(group, x, y, bestValue)];
//控制进化代数
for(int g = 0 ; g < maxGeneration ; g ++) {
//选择操作
select(group);
//根据交叉概率进行交叉
for(int i = 0 ,pre = -1 ; i < n ; i ++) {
if(random_0_1() < probCross) {
if(pre == -1) {
pre = i;
}
else{
crossOver(group[pre], group[i]);
pre = -1;
}
}
}
//根据概率进行变异
for(int i = 0 ; i < n ; i ++) {
if(random_0_1() < proMutation) {
mutate(group[i]);
}
}
//防止种群退化
double temValue;
int bestId = getOptimal(group, x, y, temValue);
if(temValue < bestValue) {
//如果种群的最优值变差,把较优的个体替换进新种群
group[bestId] = bestC;
}
else{
//如果种群的最优值变好,则更新最优值记录
bestC = group[bestId];
bestValue = temValue;
}
}
//获取最优值
getOptimal(group, x, y, value);
}
int main() {
srand(time(0));
double x, y, maxValue;
GA(x, y, maxValue);
cout<<"函数在点("<<fixed<<setprecision(15)<<x<<", "<<y<<")取得最大值:"<<maxValue<<endl;
return 0;
}
实验二-遗传算法实验(待完善)
最新推荐文章于 2023-12-18 13:30:53 发布