遗传算法解决八皇后问题
简单描述八皇后问题:具体可以移步到另一个八皇后问题
遗传算法:遗传算法(Genetic Algorithm, GA)起源于对生物系统所进行的计算机模拟研究。它是模仿自然界生物进化机制发展起来的随机全局搜索和优化方法,借鉴了达尔文的进化论和孟德尔的遗传学说。其本质是一种高效、并行、全局搜索的方法,能在搜索过程中自动获取和积累有关搜索空间的知识,并自适应地控制搜索过程以求得最佳解。
具体的流程图如下
- 选择亲代
- 计算适应度
- 淘汰掉适应度低的个体
- 进行选择操作
- 进行交叉操作
- 进行变异操作
- 产生下一代,并且进行是否符合条件,若满足则结束,若不满足,则到2循环
逐步进行操作:
1、选择亲代。
//开始直接进行初代种群
public static int[][] first_generation(){
int cout_number = 0;
int[][] generation = new int[4][8];
for (int i = 0; i < 4 ; i++) {
//直接开始子代随机五次
while(cout_number <8){
generation[i][cout_number] = (int) ((Math.random() *8));//随机生成初代0 - 7
cout_number++;
}
cout_number = 0 ;//直接重置
}
return generation;
}
2、当选择好亲代后,再计算适应度,此处是用不相互攻击的皇后对数为优解释–————*** 你可以这样理解,从第I列出发,第一个皇后,往后,每个后面的皇后和她是否碰撞或者攻击,如有+1,无就往后计算,计算完后,从第二个皇后,继续按照之前的进行计算,如此类推***
//该方法是将某个个体进行评价
public static int get_flight_queen(int[] one_geTi){
int flight_count = 0;
for (int i = 0; i < one_geTi.length-1; i++) {
for (int j = i+1; j < one_geTi.length; j++) {
if (one_geTi[i]==one_geTi[j]|((j -i) == Math.abs(one_geTi[i]-one_geTi[j]))){
flight_count++;
}
}
}
return 28 - flight_count;
}
3、完成上述步骤后,将开始选择操作
淘汰掉不合格的个体,择优进行
//把选择交叉放进函数里面,传进来后,做出了交叉选择后,再把新的一代放回数组,传回初代
public static int[][] select_generation(int[][] first_generation_array,int[] getStatus){
HashMap status_map = new HashMap();
//第一步将最少的,直接淘汰,不够优良
//第二步将top2的两个进行交叉选择
int min = Arrays.stream(getStatus).min().getAsInt();
int max = Arrays.stream(getStatus).max().getAsInt();
int min_index=0,max_index=0,last_index = 0;
for (int i = 0; i < 4 ; i++) {
if (min==getStatus[i]){
min_index = i;
}
if (max == getStatus[i]){
max_index = i;
}
}
//已经获得了下标
int random_index = (int)(Math.random()*4);
while(random_index == min_index) {
random_index = (int)(Math.random()*4);
}
//选择亲代,三个都找好了,max_index,min_index,random_index,标识下最后一个last_index;
for (int i = 0; i <getStatus.length ; i++) {
if (i!=max_index&&i!=min_index&&i!=random_index){
last_index = i;
}
}
//补位完毕
for (int i = 0; i <8 ; i++) {
first_generation_array[min_index][i] = first_generation_array[random_index][i];
}
//一切OK
int random_point_position_1 = (int)(Math.random()*8);//随机点已经选择好了
int random_point_position_2 = (int)(Math.random()*8);//随机点已经选择好了
//先对max_index 和random_index
int temp;
for (int i = random_point_position_1; i <8 ; i++) {
temp = first_generation_array[max_index][i];
first_generation_array[max_index][i]=first_generation_array[random_index][i];
first_generation_array[random_index][i] = temp;
}
//开始第二轮交换min_index 和last_index
for (int i = random_point_position_2; i <8 ; i++) {
temp = first_generation_array[min_index][i];
first_generation_array[min_index][i]=first_generation_array[last_index][i];
first_generation_array[last_index][i] = temp;
}
//交换完毕
return first_generation_array;
}
4、开始变异,几率采用10%,方法是利用随机数,小于十则表示为变异,反正不变
//变异操作,几率10%利用随机数,先看随机
private static int[][] mutations_generation(int[][] first_generation_array) {
//直接进入变异环节,变异几率10%,位置随机
for (int i = 0; i < 4 ; i++) {
int random_percent = (int) (Math.random()*100);
if (random_percent<10){
//开始变异
int mutations_postion = (int) (Math.random()*8);
int mutations_values = (int) (Math.random()*8);
first_generation_array[i][mutations_postion]=mutations_values;
}
}
return first_generation_array;
}
还有个min方法主要代码如下
while(flag){
//首先进行判断该亲代,有没有最优代,有则直接输出,没有就进行选择,交叉,变异
//1、单点交叉2、多点交叉等。这里直接使用单点交叉
System.out.println("已经执行了第"+person_number+"次数");
int[] getStatus = new int [4];//捕获当前种群的适应度函数结果
for (int i = 0; i <4 ; i++) {
int[] status = new int [8];
for (int j = 0; j < 8; j++) {
status[j] = first_generation_array[i][j];
}
getStatus[i] = get_flight_queen(status);//成功赋值
}
//先判断当前一代,有无符合
for (int i = 0; i < 4; i++) {
if (getStatus[i]==28){
System.out.println("成功找到————————————————————————————————");
for (int j = 0; j < 8; j++) {
System.out.print(" "+first_generation_array[i][j]);
}
flag = false;
break;
}
}
if (flag==false){
break;
}else {
person_number++;
//进入交叉选择
first_generation_array = select_generation(first_generation_array, getStatus);
//进入变异操作
first_generation_array = mutations_generation(first_generation_array);
}
}