zoukankan      html  css  js  c++  java
  • 路径寻找——八数码问题

    路径寻找问题可以转换为隐式图的广度遍历,目的是找到一条从初始状态到最终状态的最优路径,它不同于回溯法那样找到一个符合某些要求的解(如N皇后问题,数独问题等),回溯法是在深度遍历中进行剪枝。还要注意的是路径寻找问题是图的广度遍历不是树的广度遍历,树的广度遍历不需要判重,而图的广度遍历是需要判重的,如果不判重,时间和空间很有可能会产生浪费。

    八数码问题、倒水问题都是路径寻找问题。下面给出解决八数码问题的代码。注意它和树的BFS的异同,也注意其中使用的小技巧,如memcmp()和memcpy()。

    #include<cstdio>
    #include<cstring>
    #include<unordered_set>
    using namespace std;
    
    typedef int State[9];
    const int maxstate = 1000000;
    State st[maxstate], goal;  //用st数组模拟队列,front为队首,rear为队尾,特殊情况可能会特别定义状态结构体并使用优先队列
    int dist[maxstate]; //移动步数
    
    const int dx[] = {-1, 1, 0, 0};
    const int dy[] = {0, 0, -1, 1};
    
    unordered_set<int> vis; //C++11,底次使用hash_table,而不是像set使用rb-tree
    
    void init_lookup_table() {
        vis.clear();
    }
    
    int try_to_insert(int s) {
        int v = 0;
        for(int i = 0; i < 9; i++) v = v * 10 + st[s][i];
        if(vis.count(v)) return 0;
        vis.insert(v);
        return 1;
    }
    
    int BFS() {
        init_lookup_table(); //判重使用
        int front = 1, rear = 2;  //front表示步数,rear表示最后一个添加进去的状态所在的编号
        while(front < rear) {
            State& s = st[front];
            if(memcmp(goal, s, sizeof(s)) == 0) return front;  //找到目标
            int z;
            for(z = 0; z < 9; z++) if(!s[z]) break; //找到0的位置,也就是需要移动的格子(空白块)的位置
            
            int x = z / 3, y = z % 3; //获取行列编号
            for(int d = 0; d < 4; d++) {
                int newx = x + dx[d];
                int newy = y + dy[d];
                int newz = newx * 3 + newy; //新的空白块的位置
                if(newx >= 0 && newx < 3 && newy >= 0 && newy < 3) { //如果移动合法
                    State& t = st[rear];
                    memcpy(&t, &s, sizeof(s)); //扩展新结点
                    t[newz] = s[z];
                    t[z] = s[newz];
                    dist[rear] = dist[front] + 1;  //更新移动步数
                    if(try_to_insert(rear)) rear++;
                }
            }
            front++;  //更新移动步数
        }
        return 0;
    }
    
    int main() {
        for(int i = 0; i < 9; i++) scanf("%d", &st[1][i]);
        for(int i = 0; i < 9; i++) scanf("%d", &goal[i]);
        int ans = BFS();
        if(ans > 0) printf("%d
    ", dist[ans]); //最少移动多少步
        else printf("-1
    ");
        return 0;
    }
    
    /*
    输入:
    2 6 4 1 3 7 0 5 8
    8 1 5 7 3 6 4 0 2
    输出:
    31
    */
  • 相关阅读:
    ETL概述
    POI操作Excel常用方法总结
    段的创建表user_segments
    定位导致物化视图无法快速刷新的原因
    在shell脚本中调用sqlplus
    Oracle 字符集的查看和修改
    Java Web发布
    JSP搭建
    完全卸载oracle11g步骤:
    剑指offer——二叉排序树(BST)、平衡二叉树(AVL)
  • 原文地址:https://www.cnblogs.com/shuaihanhungry/p/5732186.html
Copyright © 2011-2022 走看看