遗传算法解决八数码难题
八数码难题是将一个数组序列通过3x3格式的拼图方式,经过多次滑动转换变成序列为“123804765”的序列。目标序列如图所示:
1 2 3
8 0 4
7 6 5
本博客使用了基因遗传算法,通过基因序列完成变换完成实验。以下将通过知识表示形式,搜索策略,搜索效率和完备性进行说明。
1.知识表示形式
在基因遗传算法中,基因是每次变化的方式,由于变换的方式只有上,下,左,右四种方式,所以只需要二进制表示方式,每两位表示一种变换方式,即“00”,“01”,“10”,“11”各表示一种变换方式,在基因序列中找到合适的序列就可以获得完成序列变换的最终结果。
同时在是否是最后的目标序列的判断上,使用了目标序列和现序列相同位置相同数字的和,当每个位置相同的时候,即为最后的变换结果。
2.搜索策略
在搜索过程中,将一代基因随机产生,通过变换判断,获取一条基因是否可以变成目标序列,当无法产生的时候,可以通过突变,交叉遗传以及选择遗传的方式,将基因遗传算法传到下一代再次进行计算,在这种算法情况下,通过设置基因长度,可以调整最长变换次数,再通过代数调整,可以对算法次数进行调整。
3.搜索效率
根据搜索参数的调整,可以改善八数码难题遗传算法的收敛速度,所以在整个代码中,选择了种群为150,基因规模为140,变异最大长度为10,交叉概率为0.75,变异概率为0.09,最大遗传代数为1000,交叉最大长度为20,精英遗传规模为10的参数。
代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <cstdlib>
#include <fstream>
#include <vector>
#include <set>
#include <algorithm>
#include <time.h>
#include <cstdlib>
using namespace std;
const double eps = 1e-10;
const int PS = 150;
const int GS = 200;
const double PC = 0.75;
const double PM = 0.09;
const int DEEP = 2000;
const double P_PS = 1.0 / PS;
const int DS = 10;
const int CMaxLen = 20;
const int MMaxLen = 10;
const int SucessValue = 440;
char ss[12];
bool findAns;
int ansId, ansLen;
int r0,c0;
struct node {
int tab[3][3];
int r, c;
int h;
}st, ed;
int ed_map[10][2];
int dir_i[4] = {
0, 0, 1, -1};
int dir_j[4] = {
1, -1, 0, 0};
///00 01 10 11
char print_op[4] = {
'l', 'r', 'u', 'd'};
struct Chromsome{
string gene;
double fitness;
double p;
bool operator<(const Chromsome &x) const {
return fitness > x.fitness;
}
};
vector<Chromsome>population[2];
double psum[2];
int now;
int next1;
int nextn;
inline int randomIdx(int x){ return rand()%x; }
inline double random(){ return (double)rand()/RAND_MAX; }
inline int check(int i, int j) {
if (i > 2 || i <