对基本遗传算法的学习
来源:互联网 发布:jst java 编辑:程序博客网 时间:2024/06/05 14:27
(→通过算法的乐趣第16章学习)
0
遗传算法是干嘛的?
貌似很高大上。
求最优解啊。
废话。
好吧就是比穷举快的随机化算法。
1
达尔文提出进化论时,肯定没想到它还会有今天这样的应用。“物竞天择,适者生存”已经成为一条真理。遗传算法就是根据这条真理而来的。
可以这么说,遗传算法就是一群(同种)小动物(解)在撕逼,弱的(基因不好)挂掉(一定概率),强的(基因好)活下来(也是一定概率( •̀ ω •́ )y),还有各种杂交,各种变异,最后撕出最牛逼的就是最优解或近似解(毕竟有随机因素)。
不是很清楚啊,那么明确下面这几个概念。
- 基因:参与计算的遗传特征
- 种群,个体:生物进化的形式为种群,而种群中的每个生物体就是一个个体
- 适者生存:强者后代多,弱者后代少
- 遗传,变异:下一代遗传上一代的部分基因,但有一定的概率基因突变
- 算法基因交叉:就是生物学的繁殖,将两个个体基因编码交换即可得到下一代个体
- 算法基因突变:直接替换个体基因中的某个或几个编码
- 算法选择:由个体的适应度,按照一定的规则从上一代种群中选择一些优良的个体遗传到下一代
就是这样
2
OK,接下来,how to do?
(流程图丑爆了)
看起来原理相当简单,实际上…
也的确很简单
3
好吧实际上好有些问题没有解决,比如说基因到底是什么鬼?
好吧,给个定义
- 遗传算法中的基因:以某种编码的形式表示的实际问题的解 then,how to code? 事实上,方法针对实际问题千变万化,举个栗子
我们有这样一些物品要放进背包,比如说5个,这事就用二进制表示某个物品是否被放进去(1为是,0为否),像酱紫 [1,1,0,1,0]
十进制就是26 这样子 还有格雷编码,符号编码,属性序列编码等等乌七八糟的 然后就不具体分析了… - 然后是适应度评估函数
适应度评估函数:首先对种群中个体的基因解码,然后根据问题空间得到其对应的结果,最后根据问题的类型和最优解的形式,按规则进行评估转换,得到个体适应度 这一串其实就是看个体的基因对问题的要求是否尽量符合,看它是否适应”环境“的程度
你可以在算法的不同阶段使用不同的函数(自适应或否),也可以简单的使用固定的函数来处理,在此不再展开 - 接着是重点——遗传算子的设计
什么是算子?广义的讲,对任何函数进行某一项操作都可以认为是一个算子。遗传算法中有三个遗传算子:选择算子、交叉算子和变异算子 下面具体分析
4
选择算子:作用是从群体中选择比较适应环境的个体复制到下一代。
介绍比例选择的策略
每个个体进入下一代的概率等于它的适应度值与整个种群中的个体适应的值总和的比例。
我们通过随机概率来选择个体,而选择概率和积累概率须事先计算
交叉算子:作用是将两个个体的基因的一部分片段互相交换,以产生新个体
介绍多点交叉的策略
对两个随机选中的个体的基因进行交换,基因交换的位置和个数都是随机选择,而交叉概率用于判断是否进行交叉运算(可以生成一随机数,判断其是否小于交叉概率),而交叉概率的大小——想想我们多少人会有后代就知道了。
变异算子:作用是直接替换基因片段,产生更好或更坏的新个体
介绍均匀变异的策略
对基因编码的每一位噫平均分布的概率进行选择,这需要变异概率,而这个概率应较低。
5
好吧,大致就是这样。遗传算法千变万化,这样的算法只是基础。
遗传算法可以用于旅行商问题,背包问题和装箱问题中,事实上基础算法的效率也不错,下面给出01背包的代码
#include <cstdlib>#include <cstdio>#include <ctime>using namespace std;#define MAX_N 40int OBJ_COUNT;int CAPACITY;const int PUNISH=0.1;//惩罚,视情况修改const int POPULATION_SIZE=32;//个体数量const int MAX_GENERATIONS=500;//进化代数const double P_XOVER=0.8;//交叉概率const double P_MUTATION=0.15;//变异概率int Weight[MAX_N];int Value[MAX_N];typedef struct GAType { int gene[MAX_N];//基因 int fitness;//适应度 double rf;//选择概率 double cf;//累积概率}GATYPE;//生成任意解void GetRandomGene(int *gene,int count) { for(int i=0;i<count;i++) gene[i]=rand()%2;}//初始化void Initialize(GATYPE *pop) { for(int i=0;i<POPULATION_SIZE;i++) { GetRandomGene(pop[i].gene,OBJ_COUNT); pop[i].fitness=0; pop[i].rf=0.0; pop[i].cf=0.0; }}//适应度评估函数int EnvaluateFitness(GATYPE *pop) { int totalFitness=0; for(int i=0;i<POPULATION_SIZE;i++) { int tw=0; pop[i].fitness=0; for(int j=0;j<OBJ_COUNT;j++) if(pop[i].gene[j]==1) { tw+=Weight[j]; pop[i].fitness+=Value[j]; } if(tw>CAPACITY) pop[i].fitness=PUNISH; totalFitness+=pop[i].fitness; } return totalFitness;}//最好情况int GetBestPopulation(GATYPE *pop,GATYPE *bestGene) { int best=0; for(int i=0;i<POPULATION_SIZE;i++) if(pop[i].fitness>pop[best].fitness) best=i; *bestGene=pop[best]; return best;}//最坏情况int GetWorstPopulation(GATYPE *pop) { int worst=0; for(int i=0;i<POPULATION_SIZE;i++) { if(pop[i].fitness<pop[worst].fitness) { worst=i; } } return worst;}void Select(int totalFitness,GATYPE *pop) { int i; GATYPE newPop[POPULATION_SIZE] = { 0 }; GATYPE best; double lastCf=0.0; for(i=0;i<POPULATION_SIZE;i++) { pop[i].rf=(double)pop[i].fitness/totalFitness; pop[i].cf=lastCf+pop[i].rf; lastCf=pop[i].cf; } GetBestPopulation(pop,&best); for(i=0;i<POPULATION_SIZE;i++) { double p=(double)rand()/(RAND_MAX+1); if(p<pop[0].cf) newPop[i]=best;//;//pop[0];// else { for(int j=0;j<POPULATION_SIZE;j++) { if((p>=pop[j].cf)&&(p<pop[j+1].cf)) { newPop[i]=pop[j+1]; } } } } for(i=0;i<POPULATION_SIZE;i++) pop[i]=(newPop[i].fitness==1)?best:newPop[i];}//基因交换void ExchangeOver(GATYPE *pop, int first, int second) { int ecc=rand()%OBJ_COUNT+1; for(int i=0;i<ecc;i++) { int idx=rand()%OBJ_COUNT; int tg=pop[first].gene[idx]; pop[first].gene[idx]=pop[second].gene[idx]; pop[second].gene[idx]=tg; }}//交叉算子设计void Crossover(GATYPE *pop) { int first=-1; for(int i=0;i<POPULATION_SIZE;i++) { double p=(double)rand()/(RAND_MAX + 1); if(p<P_XOVER) if(first<0) first=i; else { ExchangeOver(pop,first,i); first=-1; } }}//基因变异void ReverseGene(GATYPE *pop,int index) { int mcc=rand()%OBJ_COUNT+1; for(int i=0;i<mcc;i++) { int gi=rand()%OBJ_COUNT; pop[index].gene[gi]=1-pop[index].gene[gi]; }}//变异算子设计void Mutation(GATYPE *pop) { for(int i=0;i<POPULATION_SIZE;i++) { double p=(double)rand()/(RAND_MAX+1); if(p<P_MUTATION) ReverseGene(pop,i); }}const int TEST_ROUND=5;//是不是太大了int main() { srand((unsigned)time(NULL)); scanf("%d",&CAPACITY); scanf("%d",&OBJ_COUNT); for(int i=0;i<OBJ_COUNT;i++) scanf("%d%d",&Weight[i],&Value[i]); //clock_t start,finish; //double duration; //start=clock(); int success=0; GATYPE population[POPULATION_SIZE] = { 0 }; int ans=-1; for(int k=0;k<TEST_ROUND;k++) { Initialize(population); int totalFitness=EnvaluateFitness(population); for(int i=0;i<MAX_GENERATIONS;i++) { Select(totalFitness, population); Crossover(population); Mutation(population); totalFitness = EnvaluateFitness(population); } GATYPE best; GetBestPopulation(population,&best); if(best.fitness>ans) ans=best.fitness; } printf("%d\n",ans); //finish = clock(); //duration = (double)(finish-start)/CLOCKS_PER_SEC; //printf("%f seconds\n",duration); return 0;}
测试MAX_WEIGHT=300,N=10,测试次数TEST_ROUND=500时的数据时,若进化代数为500,则正确次数为470-490上下,运行时间为2s;若进化代数为100,则正确次数为400-420上下,运行时间为0.4s。
貌似不太对劲啊。。。
没错我是逗你的,上面是只有32个个体的情况
换成64呢?
测试MAX_WEIGHT=300,N=10,测试次数TEST_ROUND=500时的数据时,若进化代数为500,则正确次数为495以上,运行时间为6.75s左右;若进化代数为100,则正确次数为450-470上下,运行时间为1.5s左右。
END
ps:一个看不懂的blog
pps:另一个看不懂的blog
ppps:当然前一个是为工程服务的……
pppps:某个讲原理的ppt
- 对基本遗传算法的学习
- 遗传算法的基本代码
- 遗传算法的基本操作
- 对遗传算法的解读
- 对遗传算法理解
- 遗传算法的初步学习(一)
- 《遗传算法的数学基础》阅读笔记 (1)_遗传算法的基本性质。
- 遗传算法学习笔记
- 遗传算法学习总结
- 遗传算法学习
- 遗传算法学习材料
- 【分享】基本遗传算法源程序
- 一个封装遗传算法基本操作的类
- 基本遗传算法(SGA)的MATLAB实现
- 遗传算法(2):对适应度函数的改进
- 遗传算法与直接搜索工具箱学习笔记 十-----遗传算法的工作原理
- 遗传算法与直接搜索工具箱学习笔记 十-----遗传算法的工作原理
- 模拟退火算法和遗传算法的学习
- HDU-4734 F(x) (数位DP)
- 如何实现c语言中回调java函数
- java设计模式:单例设计模式
- 第七周项目三-用多文件组织多个类的角色
- MongoDB 1: NoSQL 和 SQL的区别
- 对基本遗传算法的学习
- 顺序表应用5:有序顺序表归并
- CSS中的无序排列转为超链接的形式
- Java中普通代码块,构造代码块,静态代码块区别及代码示例
- Spring Mvc ajax和json数据格式的配置
- C++和Java写文件(int类型)
- POJ1236【图的强连通(缩点)】
- 【Leetcode】Employees Earning More Than Their Managers
- 1003. Emergency (25)