遗传算法解决八数码难题

来源:互联网 发布: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;}
原创粉丝点击