实验目的
- 了解遗传算法的概念
- 掌握遗传算法的使用
实验内容
设计并实现一个简单的遗传算法程序,用该算法求解在区间[0,31]上的二次函数y=x2的最大值,程序能显示优化计算过程,直至给出最优解。
实验过程
问题描述
1.染色体及其编码
遗传算法以生物细胞中的染色体(chromosome)代表问题中个体对象(即可能解)。一般用字符串表示,而基因也就是字符串中的一个个字符。例如,假设数字9是某问题中的个体对象,则我们就可以用它的二进制数串1001作为它的染色体编码。
2. 适应度与适应度函数
适应度(fitness)就是借鉴生物个体对环境的适应程度,而对所求解问题中的对象(即染色体)设计的一种表征优劣的测度。适应度函数(fitness function)就是问题中的全体对象与其适应度之间的一个对应关系,即对象集合到适应度集合的一个映射。
3. 种群
种群(population)就是模拟生物种群而由若干个染色体组成的群体,它一般是整个论域空间的一个很小的子集。遗传算法就是通过在种群上实施所称的遗传操作,使其不断更新换代而实现对整个论域空间的搜索。
4. 遗传操作
遗传算法中有三种关于染色体的运算:选择-复制*、交叉和变异,称为遗传操作或遗传算子(genetic operator)。
选择-复制
选择概率P(xi)的计算公式为
其中,f为适应度函数,f(xi)为xi的适应度。
按概率选择的方法可用一种称为赌轮的原理来实现。算法中赌轮选择法可用下面的子过程来模拟:
① 在[0,1]区间内产生一个均匀分布的伪随机数r;
② 若r≤q1,则染色体x1被选中;
③ 若qk-1<r≤qk (2≤k≤N),则染色体xk被选中。
其中的qi称为染色体xi(i=1, 2, …, n)的积累概率,其计算公式为
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 4; // 种群数量
const int bit = 5;
const int iteration = 20; // 迭代次数
const double pc = 0.4; // 交叉概率
const double pm = 0.02; // 变异概率
int jubu_best = 0; // 局部
int quanju_best = 0; // 全局
int best_index = 0;
// 种群
typedef struct population
{
int bin[5];
int num;
int fit;
double p;
double q;
} pop;
// 编码 二进制->十进制
void conversion2_10(pop p[])
{
for (int i = 0; i < maxn; i++)
{
int k = 1, base = 2, sum = 0;
for (int j = 4; j >= 0; i--)
{
sum += k * p[i].bin[j];
k *= base;
}
p[i].num = sum;
}
}
// 解码 十进制->二进制
void conversion10_2(int n, int arr[])
{
for (int i = 0; i < 5; i++)
arr[i] = 0;
int j = 4;
while (n)
{
arr[j--] = n % 2;
n /= 2;
}
}
// 计算基因的适应度
void fitness(pop p[])
{
for (int i = 0; i < maxn; i++)
{
p[i].fit = p[i].num * p[i].num;
}
cout << "适应度分别为:" << endl;
for (int i = 0; i < maxn; i++)
cout << p[i].fit << " ";
cout << endl;
}
void Init_pop(pop a[])
{
for (int i = 0; i < maxn; i++)
{
int num = rand() % 32;
a[i].num = num;
conversion10_2(num, a[i].bin);
}
cout << "种群初始化为:" << endl;
for (int i = 0; i < maxn; i++)
cout << a[i].num << " ";
cout << endl;
fitness(a);
}
// 选择 ,使用轮盘赌选择法
void Select(pop p[])
{
// 适应度
fitness(p);
int sum_fit = 0;
double sumq = 0;
for (int i = 0; i < maxn; i++)
sum_fit += p[i].fit;
cout << "sum_fit:" << sum_fit << endl;
for (int i = 0; i < maxn; i++)
{
p[i].p = (double)p[i].fit / sum_fit;
sumq += p[i].p;
p[i].q = sumq;
}
cout << "概率计算:" << endl;
cout << "p:--------" << endl;
for (int i = 0; i < maxn; i++)
{
cout << p[i].p << " ";
}
cout << endl;
cout << "q:--------" << endl;
for (int i = 0; i < maxn; i++)
cout << p[i].q << " ";
cout << endl;
pop temp[maxn];
for (int i = 0; i < maxn; i++)
{
double a = (double)(rand() % 1001) * 0.001;
cout << "a:" << a << endl;
int j;
if (a < p[0].q)
{
temp[i] = p[0];
}
else
{
for (j = 1; j < maxn; j++)
{
if (a > p[j - 1].q && p[j].q)
break;
}
temp[i] = p[j];
}
}
for (int i = 0; i < maxn; i++)
p[i] = temp[i];
cout << "选择后种群为:" << endl;
for (int i = 0; i < maxn; i++)
cout << p[i].num << " ";
cout << endl;
}
// 交叉
void Crossover(pop p[])
{
for (int i = 0; i < maxn; i++)
conversion10_2(p[i].num, p[i].bin);
cout << "交叉前:--------" << endl;
for (int i = 0; i < maxn; i++)
{
for (int j = 0; j < 5; j++)
cout << p[i].bin[j] << " ";
cout << endl;
}
int n = (int)(10 * pc);
for (int i = 0; i < n; i++)
{
int a = 0, b = 0;
while (a == b)
{
a = rand() % maxn;
b = rand() % maxn;
}
int count = rand() % bit;
for (int j = 0; j < count; j++)
{
int t = p[a].bin[j];
p[a].bin[j] = p[b].bin[j];
p[b].bin[j] = t;
}
}
cout << "交叉后:--------" << endl;
for (int i = 0; i < maxn; i++)
{
for (int j = 0; j < 5; j++)
cout << p[i].bin[j] << " ";
cout << endl;
}
}
// 变异
void Mutation(pop p[])
{
cout << "变异前:--------" << endl;
for (int i = 0; i < maxn; i++)
{
for (int j = 0; j < 5; j++)
cout << p[i].bin[j] << " ";
cout << endl;
}
int n = 100 * pm;
for (int i = 0; i < n; i++)
{
int index = rand() % maxn;
int bitt = rand() % bit;
if (p[index].bin[bitt] == 0)
p[index].bin[bitt] = 1;
else
p[index].bin[bitt] = 0;
}
cout << "变异后:--------" << endl;
for (int i = 0; i < maxn; i++)
{
for (int j = 0; j < 5; j++)
cout << p[i].bin[j] << " ";
cout << endl;
}
}
int main()
{
// 初始化种群
pop p[maxn];
srand((unsigned)time(0));
Init_pop(p);
int cnt = 1;
while (cnt <= iteration)
{
for (int i = 0; i < maxn; i++)
{
if (p[i].fit > jubu_best)
jubu_best = p[i].fit;
}
cout<< "第" << cnt << "代最优解为:"<<jubu_best << endl;
if(jubu_best>quanju_best)
{
quanju_best = jubu_best;
best_index = cnt;
}
cout<< "第" << cnt+1 << "代开始运算"<< endl;
Select(p);
Crossover(p);
Mutation(p);
conversion2_10(p);
fitness(p);
cout<<"新产生的子代为:"<<endl;
for(int i=0;i<maxn;i++)
cout<<p[i].num<<" ";
cout<<endl;
cnt++;
}
cout<<"全局最优解为:"<<quanju_best<<",在第 "<<best_index<<"代!"<<endl;
return 0;
}