遗传算法
遗传算法GA(Genetic Algorithm)
是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型,是一种通过模拟自然进化过程搜索最优解的方法。遗传算法是从代表问题可能潜在的解集的一个种群(population)开始的,而一个种群则由经过基因(gene)编码的一定数目的个体(individual)组成。每个个体实际上是染色体(chromosome)带有特征的实体。染色体作为遗传物质的主要载体,即多个基因的集合,其内部表现(即基因型)是某种基因组合,它决定了个体的形状的外部表现,如黑头发的特征是由染色体中控制这一特征的某种基因组合决定的。因此,在一开始需要实现从表现型到基因型的映射即编码工作。由于仿照基因编码的工作很复杂,我们往往进行简化,如二进制编码,初代种群产生之后,按照适者生存和优胜劣汰的原理,逐代(generation)演化产生出越来越好的近似解,在每一代,根据问题域中个体的适应度(fitness)大小选择(selection)个体,并借助于自然遗传学的遗传算子(genetic operators)进行组合交叉(crossover)和变异(mutation),产生出代表新的解集的种群。这个过程将导致种群像自然进化一样的后生代种群比前代更加适应于环境,末代种群中的最优个体经过解码(decoding),可以作为问题近似最优解。
遗传算法说白了,就是模拟物种进化的原则(物竞天择,适者生存)个体与个体之间竞争,保留优秀的,继续进化的一种随机搜索算法。
遗传算法一般步骤:
(1)个体编码
(2)初始化种群(随机)
(3)*适应性评估(具体情况具体分析)( 物竞天择,适者生存)
(4)选择运算 (或称为复制运算)把当前群体中适应度较高的个体按某种规则或模型遗传到下一代群体中。一般要求适应度较高的个体将有更多的机会遗传到下一代。
(5)交叉运算: 交叉运算是遗传算法中产生新个体的主要操作过程,它以某一概率相互交换某两个个体之间的部分染色体。
(6)变异运算:变异运算是对个体的某一个或某一些基因座上的基因值按某一较小的概率进行改变,它也是产生新个体的一种操作方法。
(7)终止条件判断: 若t=T(T:最大进化次数),则以进化过程中所得到的具有最大适应度个体作为最优解输出,终止计算。提前终止:当进化一定多次后,最优解一直保持不变,可认为但前即为最优解,再进化不出更优的可提前终止。
GA算法求解过程
我们有必要先澄清几个以后将常常会碰到的概念:
极 大值、最大值、局部最优解、全局最优解。学过高中数学的人都知道极大值在一个小邻域里面左边的函数值递增,右边的函数值递减,在下图里面的表现就是一 个“山峰”。当然,在图上有很多个“山峰”,所以这个函数有很多个极大值。而对于一个函数来说,最大值就是在所有极大值当中,最大的那个。所以极大值具有局部性,而最大值则具有全局性。
下面举个经典的遗传算法用于解决问题的例子:
TSP问题(旅行商问题)
旅行商问题是指旅行家要旅行n个城市,要求各个城市经历且仅经历一次然后回到出发城市,并要求所走的路程最短.假设现在有四个城市,0,1,2,3,他们之间的代价如图一,可以存成二维表的形式:现在要从城市0出发,最后又回到0,期间1,2,3都必须并且只能经过一次,使代价最小.这就是旅行者问题.可以利用回溯法,分值界限等方法解决!
下面付代码:
/*************************************************************************
> File Name: tsp_GA.cpp
> Author: dulun
> Mail: dulun@xiyoulinux.org
> Created Time: 2016年06月20日 星期一 12时42分29秒
************************************************************************/
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<time.h>
#define LL long long
using namespace std;
const int City_Num = 10; //城市个数
const int Unit_Num = 100; //群体规模
const int Gen_Max = 500; //最大迭代数
int ps = 10; //变异概率
int length_table[10][10] = {
{0,1,1272,2567,1653,2097,1425,1177,3947,1},
{1,0,1,2511,1633,2077,1369,1157,3961,1518},
{1272,1,0,1,380,1490,821,856,3660,385},
{2567,2511,1,0,1,2335,1562,2165,3995,933},
{1653,1633,380,1,0,1,1041,1135,3870,456},
{2097,2077,1490,2335,1,0,1,920,2170,1920},
{1425,1369,821,1562,1041,1,0,1,4290,626},
{1177,1157,856,2165,1135,920,1,0,1,1290},
{3947,3961,3660,3995,3870,2170,4290,1,0,1},
{1,1518,385,993,456,1920,626,1290,1,0}
};
class Unit
{
public:
int path[City_Num];
int length;
};
bool cmp(Unit a, Unit b)
{
return a.length < b.length;
}
class Group
{
public:
Unit group[Unit_Num];
Unit best;
int best_gen;
Group()
{
best.length = 0x3f3f3f3f;
best_gen = 0;
for(int i = 0; i < Unit_Num; i++)
{
bool flag[City_Num] = {};
for(int j = 0; j < City_Num; j++)
{
int t_city = rand() % City_Num; //随机一个城市
while(flag[t_city]) //如果访问过,次随机
{
t_city = rand() % City_Num;
}
flag[t_city] = true; //直到找到一个没有访问过的
group[i].path[j] = t_city;
}
}
}
void Assess() //评估
{
for(int k = 0; k < Unit_Num; k++)
{
int rel = 0;
for(int i = 1; i < City_Num; i++)
{
rel += length_table[group[k].path[i-1]][group[k].path[i]];
}
rel += length_table[group[k].path[City_Num-1]][group[k].path[0]];
group[k].length = rel;
}
}
void Unit_Sort()
{
sort(group, group + Unit_Num, cmp);
}
Unit Cross(Unit & father, Unit & mother)
{
int l = rand() % City_Num;
int r = rand() % City_Num;
if(l > r)
{
swap(l, r);
}
bool flag[City_Num] = {};
for(int i = l; i <= r; i++)
{
flag[father.path[i]] = true;
}
Unit son;
int pos = 0;
for(int i = 0; i < l; i++)
{
while(flag[mother.path[pos]])
{
pos++;
}
son.path[i] = mother.path[pos++];
}
for(int i = l; i <= r; i++)
{
son.path[i] = father.path[i];
}
for(int i = r+1; i < City_Num; i++)
{
while(flag[mother.path[pos]])
{
pos++;
}
son.path[i] = mother.path[pos++]; //123412341234123412412
}
return son;
}
void Mutation(Unit &t) //突变
{
int proport = rand() % 100;
if(proport > ps)
{
return;
}
int one = rand() % City_Num;
int two = rand() % City_Num;
while(two != one)
{
two = rand() % City_Num;
}
swap(t.path[one], t.path[two]);
}
void Work() //进化
{
for(int i = 0; i < Gen_Max; i++)
{
if(i > 20) // 如果进化层数大于20,加大变异概率
{
ps *= 3;
}
Assess(); //评估
Unit_Sort(); //排序
if(best.length > group[0].length)
{
memcpy(&best, &group[0], sizeof(group[0]));
best_gen = i;
}
for(int j = 0; j + 2 < Unit_Num; j += 3)
{
group[j+2] = Cross(group[j], group[j+1]); //交叉
}
for(int j = 0; j < City_Num; j++)
{
Mutation(group[j]); //变异
}
}
}
void Print() //输出
{
for(int i = 0; i < Unit_Num; i++)
{
printf("No.%d path info: ", i);
for(int j = 0; j < City_Num; j++)
{
printf("%d ", group[i].path[j]);
}
printf("; All sum = %d \n", group[i].length);
}
}
};
Unit group[Unit_Num];
Unit besttone;
int Generation_Num;
int main()
{
srand( (int)time(0) );
for(int i = 0; i < 20; i++)
{
Group g;
g.Work();
g.Print();
printf("%d \n", g.best.length);
}
return 0;
}