zoukankan      html  css  js  c++  java
  • HDOJ-1043 八数码问题(A*解法)

    简介:一个九宫格中有八个数字,一位空格,每次只能移动相邻的两个格子,现要求把九宫格变为“12345678x”的样子(x代表空格)

    Sample Input
    
    2  3  4  1  5  x  7  6  8
    
     
    
    Sample Output
    
    ullddrurdllurdruldr
    

     这里我们要用到康拓展开,具体介绍如下:

    康拓展开并不难,相信各位能看懂,所以我们是把九宫格看成了一个字符串数组来解决;用BFS来寻找转移的方法,但是单纯的BFS容易TLE,那么好,我们这里就用到A*算法,A*算法其实并不难,在这里的BFS基础上我们加一个评估函数h(),h()是怎么评估的呢?是通过当前序列每个数字与标准情况下相比较(这个有点难说明白,建议看看一些迷宫类问题,即每走一步,在这一步到终点观望一下还剩多少距离)

    通过使用一个优先队列,能降低时间复杂度。相比盲目的BFS来说,是一个相对比较“智能”的算法,代码如下:

    #include<iostream>
    #include<string>
    #include<queue>
    #include<stack>
    #include<cstring>
    using namespace std;
    #define N 9
    
    struct Point
    {
        char eight[N];
        int position;
        int g,f;
        friend bool operator <(const Point& a,const Point& b)
        {
            return a.f > b.f;
        }
    }startPoint;
    
    const int fac[] = {1,1,2,6,24,120,720,5040,40320};//康托序列
    const int dir[4][2] = {{1,0},{0,1},{-1,0},{0,-1}};
    const char option[4]={'d','r','u','l'};
    bool visited[363000];
    int pre[363000];
    char op[363000];
    stack<char> stk;
    
    int cantor(Point p) //康拓展开
    {
        int ans=0;
        for(int i=0 ;i<N ;i++)
        {
            int cnt = 0;
            for(int k=i+1 ;k<N ;k++)
                if(p.eight[k]>p.eight[i])
                cnt++;
            ans += fac[8-i]*cnt;
        }
        return ans;
    }
    
    int ABS(int x){return x<0? -x:x;}  //自定义绝对值
    int h(Point p)                      //评估函数
    {
        int val=0;
        for(int i=0 ;i<N ;i++)
        {
            if(p.eight[i]=='x') continue;
            int c = p.eight[i]-'1';
            val += ABS(c/3-i/3)+ABS(c%3-i%3);
        }
        return val;
    }
    
    bool bfs()
    {
        int row,col,cantorValue;
        memset(visited,false,sizeof(visited));
        priority_queue<Point> que;
        que.push(startPoint);
        while(!que.empty())
        {
            Point p = que.top();
            que.pop();
            for(int i=0;i<4 ;i++)
            {
                row = p.position/3 +dir[i][0];
                col = p.position%3 +dir[i][1];
                if(row<0||col<0||row>=3||col>=3) continue;
                Point newPoint(p);
                newPoint.eight[newPoint.position] = newPoint.eight[col+row*3];
                newPoint.position = col+row*3;
                newPoint.eight[newPoint.position] = 'x';
                cantorValue = cantor(newPoint);
                if(visited[cantorValue]) continue;
                visited[cantorValue] = true;
                newPoint.g++;
                newPoint.f = newPoint.g +h(newPoint);
                pre[cantorValue] = cantor(p);
                op[cantorValue] = option[i];
                if(cantorValue==0) return true;
    
                que.push(newPoint);
            }
        }
        return false;
    }
    
    bool inversionNumberCheck()
    {
        int cnt =0;
        for(int i=0 ;i<N ;i++)
        {
            if(startPoint.eight[i]=='x') continue;
            for(int k=i+1;k<N ;k++)
            {
                if(startPoint.eight[k]=='x') continue;
                if(startPoint.eight[k]<startPoint.eight[i])
                    cnt++;
            }
        }
        return cnt&1;
    }
    
    int main()
    {
        while(cin >> startPoint.eight[0])
        {
            if(startPoint.eight[0]=='x')
                startPoint.position=0;
            for(int i=1 ;i<9 ;i++)
            {
                cin >> startPoint.eight[i];
                if(startPoint.eight[i]=='x')
                    startPoint.position=i;   //记录x所在的位置
            }
            if(inversionNumberCheck())
            {
                cout <<"unsolvable" <<endl;
                continue;
            }
            startPoint.g=0;
            startPoint.f = h(startPoint);
            int startCantor = cantor(startPoint);
            bfs();
            int index =0;
            while(index!=startCantor)
            {
                stk.push(op[index]);
                index = pre[index];
            }
            while(!stk.empty())
            {
                cout << stk.top();
                stk.pop();
            }
            cout << endl;
        }
    }
  • 相关阅读:
    技术期刊 · 白日照耀开鸿蒙 | 深入鸿蒙 ACE UI 框架解析;无限循环的 useEffect 类型;用 Three.js 实现 3D 房间;图神经网络入门;超基础的机器学习入门-原理篇
    青岛敏捷之旅,来了!
    痞子衡嵌入式:借助Serial Plot软件测量i.MXRT系列FlexSPI驱动Flash页编程执行时间分布
    痞子衡嵌入式:超级下载算法RT-UFL v1.0在Segger Ozone下的使用
    痞子衡嵌入式:超级下载算法RT-UFL v1.0在Keil MDK下的使用
    痞子衡嵌入式:超级下载算法RT-UFL v1.0在IAR EW for Arm下的使用
    痞子衡嵌入式:超级下载算法RT-UFL v1.0在MCUXpresso IDE下的使用
    《痞子衡嵌入式半月刊》 第 42 期
    痞子衡嵌入式:i.MXRT全系列下FlexSPI外设AHB Master ID定义与AHB RX Buffer指定的异同
    CDP客户数据管理平台体系化搭建
  • 原文地址:https://www.cnblogs.com/wxx23-IOU/p/13599493.html
Copyright © 2011-2022 走看看