zoukankan      html  css  js  c++  java
  • 八数码(BFS)

    参考白书的方法,将每一个状态映射到一个9位整数,然后再映射到它在所有状态中的大小位置(编码)来减少内存使用;

    按照 POJ eight这道题的输入形式写的(对空格的处理参考了Staigner大牛的做法:用scanf一个字符串来读取);

    输入包括初始状态和目标状态,输出为最短距离,如果无解,输出 -1;

    逆序的剪枝比较难理解:当前状态逆序数+已走步数与目标态逆序数同奇偶则有解,有解状态不会扩展出无解状态,反之也成立,初始状态的逆序数+初始态与目标态之间空格的Manhattan距离与目标态同奇偶择有解,反之无解;

    LJ 大牛提出了另一种剪枝的方法:将目标态中任意非零数互换位置得到的状态是无解状态可以达到的目标态,因此在搜索时,扩展到这些目标态表明当前状态无解;

    BFS的标记写在了出队时导致了运行速度过慢(一个31步的数据跑了1s),我一直都是这样写BFS的……多亏了LJ大牛,才降到了400ms左右!

    # include <stdio.h>
    # include <mem.h>
    # include <time.h>
    # include <math.h>
    
    # define N 362880+10
    
    typedef struct {
       char a[9];
    }state;
    
    int fact[9];
    char vis[N];
    int dis[N];
    state Q[N];
    
    const int d[4][2] = {{-1,0}, {0,1}, {1,0}, {0,-1}};
    
    void read(state* s);
    int equal(state s1, state s2);
    int compu_fact(void);
    int code(state s);
    int rev_num(state s);
    int bfs(state start, state goal);
    int manh_dis(state s1, state s2);
    
    int main()
    {
        int i, j;
        state start, goal;
        
        freopen("in.txt", "r", stdin);
        freopen("out.txt", "w", stdout);
        
        compu_fact();
    
        read(&start);
        read(&goal);   
       /* 
          if ((rev_num(start)+manh_dis(start, goal))%2 != rev_num(goal)%2) printf("-1\n"); 
    这里的剪枝不太理解,总是把可解的状态也剪掉了
    */ printf("%d\n", bfs(start, goal)); printf("time used %.3lfs.\n", (double)clock()/CLOCKS_PER_SEC); return 0; } void read(state* s) { int i; char ch[5]; for (i = 0; i < 9; ++i) { scanf("%s", ch); if (ch[0] == 'x') (*s).a[i] = 0; else (*s).a[i] = ch[0] - '0'; } } int bfs(state start, state goal) { int front, rear; int nx, ny, x, y; int i, code_t, code_nt; state t, nt; memset(vis, 0, sizeof(vis)); memset(dis, -1, sizeof(dis)); front = 1; rear = 2; Q[front] = start; dis[(code(start))] = 0; while (front < rear) { t = Q[front++]; code_t = code(t); if (equal(t, goal)) return dis[code_t]; for (i = 0; t.a[i]!=0 && i < 9; ++i) ; x = i / 3; y = i % 3; for (i = 0; i < 4; ++i) { nx = x + d[i][0]; ny = y + d[i][1]; if (nx>=0 && nx<3 && ny>=0 && ny<3) { nt = t; nt.a[3*x+y] = t.a[nx*3+ny]; nt.a[nx*3+ny] = 0; code_nt = code(nt); if (!vis[code_nt]) { vis[code_nt] = 1; Q[rear++] = nt; dis[code_nt] = dis[code_t] + 1; } } } } return -1; } int code(state s) { int i, j, cnt, ret; ret = 0; for (i = 0; i < 9; ++i) { cnt = 0; for (j = i+1; j < 9; ++j) if (s.a[j] < s.a[i]) ++cnt; ret += fact[8-i]*cnt; } return ret; } int compu_fact(void) { int i; fact[0] = 1; for (i = 1; i < 9; ++i) fact[i] = fact[i-1]*i; } int equal(state s1, state s2) { int i; for (i = 0; i < 9; ++i) if (s1.a[i] != s2.a[i]) return 0; return 1; } int rev_num(state s) { int i, j, ret; ret = 0; for (i = 0; i < 9; ++i) for (j = i+1; j < 9; ++j) if (s.a[i] > s.a[j]) ++ret; return ret; } int manh_dis(state s1, state s2) { int i, j; for (i = 0; s1.a[i]!=0 && i<9; ++i) ; for (j = 0; s1.a[j]!=0 && j<9; ++j) ; return abs(i/3 - j/3) + abs(i%3 - j%3); }

    此题已做,人生更加完整了,接下来几天打算试试别的方法(学学A*等启发式方法)。

  • 相关阅读:
    安卓开发学习日记 DAY1
    安卓开发学习日记 DAY5——监听事件onClick的实现方法
    安卓开发学习日记 DAY3——TextView,EditView,ImageView
    [原] XAF Try an XAF application that uses the Entity Framework as an ORM layer
    [原] XAF 如何使用Top
    [原] Sql Server 获取某年某月有多少个工作日(仅不包含星期日)
    [原] XAF Split View (aka MasterDetailMode=ListViewAndDetailView) improvements
    Sql Server 问题之between and 使用注意事项
    [原] XAF ListView 粘贴行或单元格
    [原] XAF How to see and edit the time part in the DatePropertyEditor for the System.DateTime property
  • 原文地址:https://www.cnblogs.com/JMDWQ/p/2502272.html
Copyright © 2011-2022 走看看