遗传算法解决8数码难题——Java

  • 什么是遗传算法
  • 什么是8数码难题
  • 解决8数码难题——Java
  • 轮盘赌算法思想
  • 代码优化
  • 参考文章

什么是遗传算法


  遗传算法是模拟达尔文生物进化伦的自然选择和遗传学激励的生物进化古欧成的计算模型,它通过模拟自然进化——适者生存,不适者淘汰,的过程搜索对于问题的最优解。


  下面描述遗传算法的基本框架:初始化一个随机种群作为第一代,种群中的个体通过基因实现唯一性,针对我们要解决的问题,不同基因的个体存在不同的适应性,适者生存,不适者被淘汰,通过大自然的选择,存活下来的所有个体进行遗传变异操作,产生第二代的个体。重复前面的选择遗传变异等过程,直到找到完美解决问题,即适应性达到完美的个体,此时该个体的基因就是解决问题的方案。


  基因:将问题中对象可以进行的所有操作,通过编码的方式,形成基因序列;

  ​初始化:设置第一代种群中所有个体的基因序列,此过程为初始化,为了后续进行选择,遗传,以及编译过程做准备;

  ​适应性:即个体对于环境的适应性,或者称为方案解决问题的能力,通过设置适应性函数计算个体的适应性;

  ​选择:大自然将适应性高的个体选择出来并使得存活,同时部分不适应的个体也幸运地存活下来,此过程称为选择;

  ​遗传:两个个体将自身优秀的基因传承给后代的过程,即构成下一代基因序列过程的一部分;

  ​变异:两个个体在遗传的过程中产生一定不可控变化的过程,即构成下一代基因序列过程的一部分。

什么是8数码难题


  在一个3×3的棋盘中,摆有8个棋子,每个棋子上标有1-8的8个数字,且各不相同,棋盘上还有一个空格,与空格相邻的棋子可以移到空格中。给出一个初始状态和一个终止状态,求初始状态到终止状态的转变过程。

解决8数码难题——Java

​  个体定义的代码:

public class Self{public static boolean keyAns;public int[] gene;        //基因序列public int location;  //记录满足条件的最终步数所在的位置public int fitness;       //个体对环境的适应度public int rf;           //个体适应度占群体总适应度的比例public int cf;         //个体i的累积适应度public Self(){Random ran=new Random();gene=new int[140];   //假定基因的长度为140for(int i=0;i<gene.length;i++){gene[i]=ran.nextInt(4)+1;//对应空白格的上下左右移动}location=-1;   //记住这个“-1”keyAns=false;rf=0;cf=0;}
}

​  空白格进行移动:

public static boolean move(int sta,int[] nowSta){int space=0;       //空格的位置int block=0;        //移动的格子的位置//查找空格的位置for(int i=0;i<nowSta.length;i++){if(nowSta[i]==0){space=i;block=space;break;}}//九宫格的架构为// 0 1 2// 3 4 5// 6 7 8//确定传入的sta所代表的操作,所代表的需要移动的格子的位置//例如,空格在“4”位置,传入sta为1,确认移动格子的位置为“1”if(sta==1){if(space>=3){block=block-3;}}//空格向上移动else if(sta==2){if(space<=5){block=block+3;}}//空格向下移动else if(sta==3){if(space%3>=1){block=block-1;}}//空格向左移动else if(sta==4){if(space%3<=1){block=block+1;}}//空格向右移动int temp=nowSta[space];nowSta[space]=nowSta[block];nowSta[block]=temp;//交换两个格子中的值if(space==block)return false;elsereturn true;  //sta代表的操作可以被执行,用于打印变化过程
}

​  计算单个基因实施的操作(即一次移动)对于适应度的改变:

public static int count(int[] nowSta,int[] goalSta){int Fit=0;for(int i=0;i<nowSta.length;i++){if(nowSta[i]==goalSta[i]){Fit=Fit+100-(nowSta[i]*10);}//适应度计算的具体方法,可根据个人需要进行修改}return Fit;
}

​  计算个体的适应度:

public void countFitness(int[] nowSta,int[] goalSta){for(int i=0;i<gene.length;i++){move(gene[i],nowSta);fitness=count(nowSta,goalSta);if(fitness==540){//找到解决方案时退出循环,将静态变量kayAns改为true作为判断条件location=i;keyAns=true;break;}}if(fitness==0){fitness=1;}//即使适应度为0,也有被选择的可能性(具体见选择算法和轮盘赌算法)
}

​  基因变异:

public void varyWay(){Random ran=new Random();int num=ran.nextInt(140)+1;     //有几个基因发生变异for(int i=0;i<num;i++){int loca=ran.nextInt(140); //随机定位gene[loca]=5-gene[loca]; //变异对于基因变异的影响方式//可以根据需要自行修改}
}
public void vary(){Random ran=new Random();//有一定的概率fvary发生基因变异//double fvary=0.30;//double freal=ran.nextDouble();//一开始用的是double比较,重新看了一遍觉得还是改一下,可不用double比较就不用int fvary=3;int freal=ran.nextInt(10+1);if(freal<=fvary){varyWay();}
}

​  因为定义的是Self类,即个体类,剩下还有选择(运用了轮盘赌的思想,针对群体)以及基因交叉(需要两个个体)的操作写在了main方法中,如下:

public static void main(String[] args){int[] firstState={7,2,4,5,0,6,8,3,1};int[] goalState={0,1,2,3,4,5,6,7,8};int[] nowState={7,2,4,5,0,6,8,3,1};int[][] prea=new int[20][140];Self[] a=new Self[20];         //假设种群的个体数目为20for(int i=0;i<a.length;i++){a[i]=new Self();}//假设最大的种群代数是9999for(int ration=0;ration<9999;ration++){int totalFitness=0;//计算个体的适应度for(int i=0;i<a.length;i++){//对于一个个体的适应度计算完毕之后,需要将nowState重新初始化for(int k=0;k<nowState.length;k++){nowState[k]=firstState[k];}a[i].countFitness(nowState,goalState);totalFitness=totalFitness+a[i].fitness;}if(a[0].keyAns){  //如果种群中出现完美个体,退出循环break;}int lastCf=0;      //第i个体的累积适应度for(int i=0;i<a.length;i++){a[i].rf=a[i].fitness*1000000/totalFitness;a[i].cf=lastCf+a[i].rf;lastCf=a[i].cf;}//至此完成种群的初始化,下面开始实现种群的选择//采用轮盘赌算法的思想,将适应环境的个体选到二维数组prea中/*因为使用double类型的变量做轮盘赌算法的运算时,会因为精度丢失的原因使得比较结果出现异常,导致被选择的基因为空,prea数组自动填0补充。使用int类型放大1000000倍,会出现个体的累积选择概率总和不为1的情况,所以当出现了这种情况的时候,默认将数组最后的一个个体选择为下一代的父体(母体)。*/Random ran=new Random();for(int i=0;i<a.length;i++){int f=ran.nextInt(1000000);if(f<a[i].rf){for(int k=0;k<a[i].gene.length;k++){prea[i][k]=a[i].gene[k];}}else{if(f>a[19].cf){for(int k=0;k<a[i].gene.length;k++){prea[i][k]=a[19].gene[k];}}else{for(int j=0;j<19;j++){if(f>=a[j].cf && f<a[j+1].cf){for(int k=0;k<a[i].gene.length;k++){prea[i][k]=a[j+1].gene[k];}break;}}}}}for(int i=0;i<a.length;i++){for(int k=0;k<a[i].gene.length;k++){a[i].gene[k]=prea[i][k];}}//至此完成选择函数,下面开始实现遗传//遗传需要两个个体进行基因交叉,当first不为-1时发生int first=-1;int fChange=8;       //基因交换的概率for(int i=0;i<a.length;i++){int f=ran.nextInt(10)+1;if(f<=fChange){if(first=-1){first=i;}else{int num=ran.nextInt(140)+1;for(int j=0;j<num;j++){int loca=ran.nextInt(140)+1;int temp;temp=a[i].gene[loca];a[i].gene[loca]=a[first].gene[loca];a[first].gene[loca]=temp;}}}}//至此完成基因交叉,下面实现基因变异//调用之前定义的基因突变方法for(int i=0;i<a.length;i++){a[i].vary();}}//基因突变结束后形成了新的种群,回归for循环的开头执行自然选择的过程,直到出现完美个体,找到keyAns后通过break跳出循环//跳出循环后,根据Self的属性location(定位结束动作,初始值为-1)不为-1定位完美个体在种群中的位置int thenum=0;for(int i=0;i<a.length;i++){if(a[i].location!=-1){thenum=i;break;}}for(int i=0;i<a[thenum].location+1;i++){if(move(a[thenum].gene[i],firstState)){//move(int sta,int[] nowSta)返回boolean类型变量//打印变化过程System.out.print(……);System.out.print(……);System.out.print(……);System.out.println(……);}}
}

轮盘赌算法思想

  轮盘赌在代码中的应用体现在选择算法中,具体应用过程大概如下:

  • 对于种群中的第一个个体,产生一个概率p,如果该个体在种群中的适应度贡献rf(个体适应度/总适应度)大于概率p,则此个体被选择;

  • 如果rf小于p,则利用累积概率cf选出个体,规则如下,按照数组的顺序计算每个个体的累积概率cf,如a[0]的累积概率为a[0].rf,a[1]的累积概率为a[0].rf+a[1].rf,……然后使得a[i].rf<=p<a[i+1].rf,选择个体a[i];

  • 因为使用double类型的变量做轮盘赌算法的运算时,会因为精度丢失的原因使得比较结果出现异常,导致被选择的基因为空,prea数组自动填0补充。使用int类型放大1000000倍,会出现个体的累积选择概率总和不为1的情况,所以当出现了这种情况的时候,默认将数组最后的一个个体选择为下一代的父体(母体)。

    对于轮盘赌算法如果想要了解更详细建议查找相关文章!!!

代码优化

  1. 一开始将种群代数设置为999,但是得到false(找不到解决方案)的结果,将种群最大代数设置为9999之后则得到了结果。同时,上调基因突变的概率以及基因交叉的概率可加快得到解决方案的速度(减少代数)。

  2. 一开始设想是在Self类外设置一个类Race用来存放Self,这样就可以在main方法外写选择以及基因交叉等操作的方法,优化代码结构。但是当时刚学Java,对于面向对象还学得不是很理解,尝试了之后发现代码反复报错就放弃了,因此写在了一个文件中,main方法中显得结构混乱。

参考文章

  机器学习–遗传算法解决八数码问题(含python代码)

遗传算法解决8数码难题——Java相关推荐

  1. 深度优先搜索解决八数码难题

    八数码问题 以前用java写的通过深度优先瘦素解决八数码难题. 对于八数码难题来说,可以把9宫格看成一个[3][3]的二维数组,将空格位置看成0,将0可以移动的方向看成树的枝丫,分为上下左右4个方向. ...

  2. A*算法解决八数码问题 Java语言实现

    A*算法解决八数码问题 Java语言实现 参考文章: (1)A*算法解决八数码问题 Java语言实现 (2)https://www.cnblogs.com/beilin/p/5981483.html ...

  3. 遗传算法解决八数码问题

    参考:百度百科,wiki, 论文<基于遗传算法的八数码问题的设计及实现>,论文<选择算子和遗传算法的计算效率分析>,论文:<改进的遗传算子选择算法> http:// ...

  4. 遗传算法解决数独suduko难题,附python代码实现

    定义 数独是源自18世纪瑞士的一种数学游戏.是一种运用纸.笔进行演算的逻辑游戏.玩家需要根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行.每一列.每一个粗线宫(3*3)内的数字均含1 ...

  5. Nilsson's sequence score算法解决八数码问题解释

    解决了最近一个人工智能关于解决八数码难题的作业. 图可能看不清,除了黑块外其他位置是英文字母ABCDEFGH A*:f(n)=g(n)+h(n) 其中f为总花费,g为已知花费(深度),h为估计花费 关 ...

  6. 遗传算法解决八皇后问题(java源码)

    本文源码下载链接:https://download.csdn.net/download/goulvjiang3176/11221063 另有贪心算法解决八皇后问题的源码下载链接:https://dow ...

  7. 8puzzle java 代码_八数码难题(8 puzzle)深度优先和深度优先算法

    1搜索策略 搜索策略是指在搜索过程中如何选择扩展节点的次序问题.一般来说,搜索策略就是采用试探的方法.它有两种类型:一类是回溯搜索,另一类是图搜索策略. 2盲目的图搜索策略 图搜索策略又可分为两种:一 ...

  8. 习题:八数码难题(双向BFS)

    八数码难题(wikioi1225) [题目描述] 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出 ...

  9. matlab 遗传优化算法_转载 | 遗传算法解决TSP问题的MATLAB实现

    问题定义: 巡回旅行商问题 给定一组n个城市和俩俩之间的直达距离,寻找一条闭合的旅程,使得每个城市刚好经过一次且总的旅行距离最短. TSP问题也称为货郎担问题,是一个古老的问题.最早可以追溯到1759 ...

最新文章

  1. 网络工程师_记录的一些真题_2008下半年上午
  2. qt windows 静态编译_VS+QT工程配置问题
  3. 知乎热议:高数、线代应该成为计算机专业学习的重心吗?
  4. TPYBoard开发板搭建与阿里云服务发送数据
  5. return 、break 和 continue的区别
  6. python之提升程序性能的解决方案
  7. openerp one2many 字段排序
  8. 蓝桥杯刷题 -- 第六届蓝桥杯
  9. Java 算法 - 递归算法思想
  10. 注册reg.html是什么,reg命令如何修改注册表?reg命令作用介绍
  11. 中国GDP与百姓收入
  12. html中的embed标签属性,html中Embed标签的语法和属性设置
  13. 位运算符(,|,~,^,同或,>>,<<)
  14. SpaceSyntax【空间句法】之DepthMapX学习:第三篇 软件介绍与一般分析流程图
  15. HDMI接口简介---分辨率 时钟频率 lane速率计算
  16. android学生成绩查询代码,android学生成绩查询系统.pdf
  17. 超有爱的并查集 6666
  18. python猜拳游戏电脑随机循环版
  19. 《纽约时报》发文评选掀起区块链革命的10位代表性人物,吴忌寒上榜
  20. AnG-顶级的数字营销服务和软件提供商-http://www.agrant.cn

热门文章

  1. WPF学习第九集-深入浅出话命令
  2. 软件测试技术工程师面试这些离职原因不能说!
  3. 外部用户触达方式有哪些?应用场景是什么?
  4. 创新终端!搭载展锐芯的作业帮智能辅导机来啦!
  5. OceanBase 社区版下载部署指引
  6. MacOS中afconvert的使用(音频格式转换)
  7. Win7安装新应用时提示Another installation is in progress
  8. 【C语言习题】有3个学生,上4门课程,要求输入全部学生的各门课成绩,并分别求出每门课的平均成绩(用二维数组编程)
  9. 2022 Neural Networks期刊边缘检测网络FCL-Net论文精读
  10. 基于OSG 和FCL 的碰撞仿真