更新最优值。
改进之后的效果如下所示,显然比之前更优,且实验结果显示对于前面对比实验中的参数值,这里只需要较小的参数(如迭代次数只需2000次)值即可稳定收敛到此最大值,可知改进非常有效。
增加输出精度之后为,于是得到最优的结果为2.894471354862841
源代码
改进后的源代码如下:
#include
// 程序欲分配内存的数组大小
const int mxn = 10000; // 最大的种群规模 const int mxlen = 1000;
// 遗传算法关键参数 const int N = 200; const int len = 30;
// 种群的个体数
// 每个个体的染色体的长度,x和y各占一半 // 交叉操作时多点交叉的交叉点个数 // 最大的染色体长度
const int crossnum = 4;
const int maxGeneration = 2000; // 最大进化代数
const double probCross = 0.85;
// 个体的染色体类 class Chromosome { public: };
double bestval;
// 交叉概率
const double probMutation = 0.15; // 变异概率
bool g[mxlen]; // 二进制编码的编码数组 Chromosome() { }
Chromosome(const Chromosome& c) // 拷贝构造函数,进行深复制 { }
void operator=(const Chromosome& c) // 重载=号,进行深复制 { }
for (int i = 0; i < len; i++) g[i] = c.g[i]; for (int i = 0; i < len; i++) g[i] = c.g[i]; for (int i = 0; i < len; i++) g[i] = rand() % 2;
// 默认构造函数,构造随机染色体
// 记录当前所得的最优值
// 个体的种群,辅助数组
Chromosome bestC; // 记录当前最优值对应的个体染色体 Chromosome group[mxn], temGroup[mxn];
// 目标函数
double f(double x, double y) { }
// 解码函数,从染色体得到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 = 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 = q * 2; x = 1 + (2 - 1) / num * tem;
return x * sin(6 * y) + y * cos(8 * x);
}
// 适应度函数,为避免负值,把目标函数加一个正数 double fitness(const Chromosome& c) { }
// 辅助函数,生成0-1之间的随机小数 double inline random01() { }
// 选择操作
void select(Chromosome group[mxn]) {
// 计算每个个体的选择概率 double fitnessVal[mxn];
for (int i = 0; i < N; i++) fitnessVal[i] = fitness(group[i]); double sum = 0;
for (int i = 0; i < N; i++) sum += fitnessVal[i]; double prob[mxn];
for (int i = 0; i < N; i++) prob[i] = fitnessVal[i] / sum; // 随机选择N个个体组成新种群 int selectId[mxn];
for (int i = 1; i < N; i++) prob[i] += prob[i-1]; for (int i = 0; i < N; i++) {
// 使用轮盘赌算法选择个体
double randNum = random01(); int j;
for (j = 0; j < N - 1; j++) { }
if (j == N - 1)
selectId[i] = j; if (randNum < prob[j]) { }
selectId[i] = j; break;
return rand() % 10000 / 10000.0; double x, y; decode(c, x, y); return f(x, y) + 5;
}
}
// 把种群更新为新选择的个体集合 for (int i = 0; i < N; i++) for (int i = 0; i < N; i++)
temGroup[i] = group[i];
group[i] = temGroup[selectId[i]];
// 交叉操作,使用多点交叉
void crossover(Chromosome& c1, Chromosome& c2) { }
// 变异操作
void mutate(Chromosome& c) { }
// 获取种群最优个体
int getOptimal(Chromosome group[mxn], double& x, double& y, double& val) {
// 计算适应值,遍历得到最优值并进行解码 double fitnessVal[mxn]; // 随机选择一位进行翻转 int i = rand() % len; c.g[i] = !c.g[i]; // 生成交叉点位置,并排序 int crosspoint[mxn];
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) { }
// 如果若干个交叉点重合,则效果叠加 // 偶数个交叉点效果相当于没有交叉点
while(j < crossnum && i == crosspoint[j]) { }
j++;
flag = !flag;
swap(c1.g[i], c2.g[i]); if (i == crosspoint[j])
}
for (int i = 0; i < N; i++) fitnessVal[i] = fitness(group[i]); int id = 0;
for (int i = 1; i < N; i++)
if (fitnessVal[i] > fitnessVal[id])
id = i;
decode(group[id], x, y); val = f(x, y); return id;
// 遗传算法总代码
void GA(double& x, double& y, double& val) {
//
bestC = group[getOptimal(group, x, y, bestval)];
// 控制进化代数
for (int g = 0; g < maxGeneration; g++) {
// 选择操作 select(group); // 根据交叉概率进行交叉
for (int i = 0, pre = -1; i < N; i++) { }
// 根据变异概率进行变异
for (int i = 0; i < N; i++)
if (random01() < probMutation)
mutate(group[i]); if (random01() < probCross) { }
if (pre == -1) { }
crossover(group[pre], group[i]); pre = -1; pre = i; else
// 初始化种群
for (int i = 0; i < N; i++)
group[i] = Chromosome();