遗传算法解决八数码难题
来源:互联网 发布:nginx服务器绑定域名 编辑:程序博客网 时间:2024/06/16 21:03
遗传算法解决八数码难题
八数码难题是将一个数组序列通过3x3格式的拼图方式,经过多次滑动转换变成序列为“123804765”的序列。目标序列如图所示:
1 2 38 0 47 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 11char 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 < 0 || j > 2 || j < 0) return 0; return 1;}int get_h(node a){ int h = 0; for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) if (a.tab[i][j] && a.tab[i][j] == ed.tab[i][j]) h += 100 - a.tab[i][j] * 10; return h;}int getFitnessValue(int id, node a){ int ret = 0; int nextr, nextc; string s = population[now][id].gene; for (int i = 0; i < GS; i += 2) { int x = (s[i] + s[i]) + s[i + 1]; nextr = a.r + dir_i[x]; nextc = a.c + dir_j[x]; if (check(nextr, nextc)) { swap(a.tab[nextr][nextc], a.tab[a.r][a.c]); swap(nextr, a.r); swap(nextc, a.c); ret = max(ret, get_h(a)); if (ret == SucessValue) { findAns = true; ansId = id; ansLen = i + 2; return ret; } } } return ret;}void calc(){ psum[now] = 0; for (int i = 0; i < PS; i++) { population[now][i].fitness = getFitnessValue(i, st); if (findAns) return ; psum[now] += population[now][i].fitness; } //sort(population[now].begin(), population[now].end()); for (int i = 0; i < PS; i++){ population[now][i].p = (1.* population[now][i].fitness) / psum[now]; //printf("%.1f ",population[now][i].fitness); } //printf("\n");}void init() { srand((unsigned long)time(0));//随机种子 population[0].clear(); population[1].clear(); now = 0; next1 = now ^ 1; for (int i = 0; i < PS; i++) { Chromsome ss; population[now].push_back(ss); population[next1].push_back(ss); for (int j = 0; j < GS; j++) { population[now][i].gene += randomIdx(2); } }}int Selection(){ double nn = 0; double mm = random(); for (int i = 0; i < PS; i++) { nn += population[now][i].p; if (nn >= mm) { return i; } } return PS - 1;}void crossover(int x, int y){ int low = randomIdx(GS); int len = randomIdx(CMaxLen); len = min(len, GS - low - 1); for (int i = low; i <= low + len; i++) swap(population[next1][x].gene[i], population[next1][y].gene[i]);}void mutation(int x){ int i = randomIdx(GS); int low = x; int len = randomIdx(MMaxLen); len = min(len, GS - low - 1); for (int i = x; i < low + len; i++) population[next1][x].gene[i] ^= 1;}void out(string s, int len){ vector<int>ans; ans.clear(); int nextr, nextc; int r = st.r, c = st.c; for (int i = 0; i < len; i += 2) { int x = (s[i] + s[i]) + s[i + 1]; nextr = r + dir_i[x]; nextc = c + dir_j[x]; if (check(nextr, nextc)) { swap(nextr, r); swap(nextc, c); int vs = ans.size(); if (vs && ans[vs - 1] != x && ans[vs - 1] / 2 == x / 2) { ans.pop_back(); continue; } ans.push_back(x); } } char ss1[12]; for(int i = 0; i < 12; i ++){ ss1[i] = ss[i]; } printf("\n原拼图:\n"); printf("%d %d %d\n",st.tab[0][0],st.tab[0][1],st.tab[0][2]); printf("%d %d %d\n",st.tab[1][0],st.tab[1][1],st.tab[1][2]); printf("%d %d %d\n\n",st.tab[2][0],st.tab[2][1],st.tab[2][2]); for (int i = 0; i < ans.size(); i++){ if(print_op[ans[i]] == 'l'){ st.tab[st.r][st.c] = st.tab[st.r][st.c+1]; st.tab[st.r][st.c+1] = 0; st.c = st.c + 1; printf("第 %d 次操作:向左滑动\n",i+1); printf("%d %d %d\n",st.tab[0][0],st.tab[0][1],st.tab[0][2]); printf("%d %d %d\n",st.tab[1][0],st.tab[1][1],st.tab[1][2]); printf("%d %d %d\n\n",st.tab[2][0],st.tab[2][1],st.tab[2][2]); } else if(print_op[ans[i]] == 'r'){ st.tab[st.r][st.c] = st.tab[st.r][st.c-1]; st.tab[st.r][st.c-1] = 0; st.c = st.c - 1; printf("第 %d 次操作:向右滑动\n",i+1); printf("%d %d %d\n",st.tab[0][0],st.tab[0][1],st.tab[0][2]); printf("%d %d %d\n",st.tab[1][0],st.tab[1][1],st.tab[1][2]); printf("%d %d %d\n\n",st.tab[2][0],st.tab[2][1],st.tab[2][2]); } else if(print_op[ans[i]] == 'u'){ st.tab[st.r][st.c] = st.tab[st.r+1][st.c]; st.tab[st.r+1][st.c] = 0; st.r = st.r + 1; printf("第 %d 次操作:向上滑动\n",i+1); printf("%d %d %d\n",st.tab[0][0],st.tab[0][1],st.tab[0][2]); printf("%d %d %d\n",st.tab[1][0],st.tab[1][1],st.tab[1][2]); printf("%d %d %d\n\n",st.tab[2][0],st.tab[2][1],st.tab[2][2]); } else if(print_op[ans[i]] == 'd'){ st.tab[st.r][st.c] = st.tab[st.r-1][st.c]; st.tab[st.r-1][st.c] = 0; st.r = st.r - 1; printf("第 %d 次操作:向下滑动\n",i+1); printf("%d %d %d\n",st.tab[0][0],st.tab[0][1],st.tab[0][2]); printf("%d %d %d\n",st.tab[1][0],st.tab[1][1],st.tab[1][2]); printf("%d %d %d\n\n",st.tab[2][0],st.tab[2][1],st.tab[2][2]); } } puts("");}void out_table(node a);void GA(){ init(); int x, y; int dep = 0; findAns = 0, ansId = -1, ansLen = GS; while (dep != DEEP) { calc(); if (findAns) break; nextn = 0; while (nextn < PS) { Chromsome tmp; int fla = 0; x = Selection(); y = Selection(); while(x == y) y = Selection(); population[next1][nextn++] = population[now][x]; population[next1][nextn++] = population[now][y]; double xx = random(); if (xx < PC) { crossover(nextn - 1, nextn - 2); } xx = random(); if (xx < PM) { for(int i = 0; i <= 2 * dep / 10; i++) mutation(nextn - 1); } xx = random(); if (xx < PM) { for(int i = 0; i <= 2 * dep / 10; i++) mutation(nextn - 2); } } next1 = now; now ^= 1; dep++; } if (findAns) out(population[now][ansId].gene, ansLen); cout << "代数: " << dep<< " 代" << endl;}void solve(){ if (get_h(st) == SucessValue) return ; else GA();}void out_table(node a) { for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) cout << a.tab[i][j] << ' '; cout <<endl; } cout <<endl;}void input(node &st) { char ch; for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) { scanf(" %c", &ch); if (ch <= '9' && ch > '0') st.tab[i][j] = ch - '0'; else { st.r = i; st.c = j; st.tab[i][j] = 0; } }}void In(char s[], node &st){ char ch; int next = 0; for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) { while (s[next] == ' ') next++; ch = s[next++]; if (ch <= '9' && ch > '0') st.tab[i][j] = ch - '0'; else { st.r = i; st.c = j; st.tab[i][j] = 0; r0 = i; c0 = j;} }}void pre(){ ed.tab[0][0] = 1; ed.tab[0][1] = 2; ed.tab[0][2] = 3; ed.tab[1][0] = 8; ed.tab[1][1] = 0; ed.tab[1][2] = 4; ed.tab[2][0] = 7; ed.tab[2][1] = 6; ed.tab[2][2] = 5; for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) if (ed.tab[i][j]) { ed_map[ed.tab[i][j]][0] = i; ed_map[ed.tab[i][j]][1] = j; }}int get_preval(node a) { int ret = 0; for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) { if (!a.tab[i][j]) continue; int x = 0; for (int jj = j + 1; jj < 3; jj++) if (a.tab[i][jj] && a.tab[i][jj] < a.tab[i][j]) x++;/// for (int ii = i + 1; ii < 3; ii++) for (int jj = 0; jj < 3; jj++) if (a.tab[ii][jj] && a.tab[ii][jj] < a.tab[i][j]) x++; ret += x; } return ret % 2;}bool pre_solve() { return (get_preval(st) ^ get_preval(ed));}int main(){ pre(); while (gets(ss)) { In(ss, st); if (pre_solve()) puts("没有结果\n"); else solve(); } return 0;}
阅读全文
0 0
- 遗传算法解决八数码难题
- 遗传算法解决八数码问题之一
- 遗传算法解决八数码问题
- 八数码难题源代码
- 【宽搜】八数码难题
- wikioi1225 八数码难题
- wikioi1225 八数码难题
- ## 八数码难题 ##
- Codevs1225 八数码难题
- 八数码难题
- 八数码难题
- 八数码难题
- 八数码难题
- 八数码难题
- luoguP1379八数码难题
- 1225 八数码难题
- 八数码难题
- P1379 八数码难题
- 面向对象的基本特征
- python 深入理解 赋值、引用、拷贝、作用域
- Linux 信号详解一(signal函数)
- ajax请求不进入success函数的原因
- SpringBoot整合thymeleaf模板
- 遗传算法解决八数码难题
- python uniform 函数
- 7个高级技巧帮助你释放大量Mac OS X硬盘空间
- android 5.0新增的控件总结
- 第四章 贵族专制、民主政治和系统设计
- 坐标转换
- caffe--net.cpp解析
- Linux 学习思维导图
- 怎样查外键建在哪个表上,查看约束【转载】