zoukankan      html  css  js  c++  java
  • codevs1225 八数码难题

    题目描述 Description

    Yours和zero在研究A*启发式算法.拿到一道经典的A*问题,但是他们不会做,请你帮他们.
    问题描述

    在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。

    输入描述 Input Description

    输入初试状态,一行九个数字,空格用0表示

    输出描述 Output Description

    只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊无法到达目标状态数据)

    样例输入 Sample Input

    283104765

    样例输出 Sample Output

    4

    数据范围及提示 Data Size & Hint

    详见试题

    思路:

    (康托展开+双向广搜) or ida*

    代码:

    ①双向广搜:

    #include<iostream>
    #include<cstdio>
    #include<string>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #include<algorithm>
    #define mx 4000000
    using namespace std;
    
    struct chess{
        int node[9];
        int step;
        int pos;
        bool cla;
    };
    int chart = 0,step[2][10000];
    map<int,int> trans[2];
    chess start,end;
    bool jud[2][mx];
    int m_jud[9][4] = {1,3,-1,-1,
                       0,4,2,-1,
                       1,5,-1,-1,
                       0,4,6,-1,
                       1,3,5,7,
                       2,4,8,-1,
                       3,7,-1,-1,
                       4,6,8,-1,
                       5,7,-1,-1};
    
    int getval(chess x){
        int res = 1,val = 0;
        for(int i = 1;i <= 9;i++){
            val += res * x.node[i-1];
            res *= (i+1);
        }
        return val;
    }
    void putout(chess pt){
        cout<<"the class:"<<pt.cla<<endl;
        for(int i = 1;i <= 3;i++){
            for(int j = 1;j <= 3;j++){
                cout<<pt.node[(i-1) * 3 + j - 1] <<" ";
            }
            cout<<endl;
        }
        cout<<"steps: "<<pt.step<<" , pos: "<<pt.pos<<endl;
    }
    void init(){
        int co,md = 1;
        cin>>co;
        for(int i = 8;i >= 0;i--){
            start.node[i] = (co / md)% 10;
            md *= 10;
            if(start.node[i] == 0) start.pos = i;
            
        }
        start.cla = 0;
        end.node[0] = 1;
        end.node[1] = 2;
        end.node[2] = 3;
        end.node[3] = 8;
        end.node[4] = 0;
        end.node[5] = 4;
        end.node[6] = 7;
        end.node[7] = 6;
        end.node[8] = 5;
        end.step = start.step = 0;
        end.pos = 4;
        end.cla = 1;
    }
    void bfs(){
        queue<chess> now,then;
        now.push(start);
        now.push(end);
        chess test,h;
        int p,code;
        while(!now.empty()){
            h = now.front();
            p = h.pos;
            code = getval(h);
            trans[h.cla][code] = chart;
            step[h.cla][chart] = h.step;
            chart++;
            jud[h.cla][code] = 1;
            for(int i = 0,j = m_jud[p][i];j != -1 && i <= 3;i++,j = m_jud[p][i]){
                test = h;
                test.step++;
                swap(test.node[p],test.node[j]);
                code = getval(test);
                //if(jud[test.cla][code]) continue;
                test.pos = j;
                trans[test.cla][code] = chart;
                step[test.cla][chart] = test.step;
                chart++;
                if(jud[!test.cla][code]){
                    cout<<step[0][trans[0][code]] + step[1][trans[1][code]]<<endl;
                    return;
                }
                if(!jud[test.cla][code]){
                    now.push(test);
                    jud[test.cla][code] = 1;
                }
                
            }
            now.pop();
        }
    }
    int main(){
    
        init();    
        bfs();
        return 0;
    }

    ②IDA*:

    #include <iostream>
    #include <cmath>
    #include <cstdlib>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    const unsigned int M = 1001;
    int dir[4][2] = {
        1, 0, // Down
        -1, 0, // Up
        0,-1, // Left
        0, 1 // Right
    };
    typedef struct STATUS{
        int arr[3][3];
        int r,c;
    }STATUS;
    char dirCode[] = {"dulr"};
    char rDirCode[] = {"udrl"};
    char path[M]; // 最优解
    STATUS begin, end = { 1,2,3,4,5,6,7,8,0,2,2 }; // 起始和终止状态
    int maxDepth = 0; // 深度边界
    int diff(const STATUS &cur) // 启发函数
    {
        int i,j,k,m,ans=0;
        for(i=0;i<=2;i++)
            for(j=0;j<=2;j++)
            {
                if(cur.arr[i][j] != 0)
                {
                    for(k=0;k<=2;k++)
                        for(m=0;m<=2;m++)
                        {
                            if(cur.arr[i][j] == end.arr[k][m])
                            {
                                ans+=abs(i-k)+abs(j-m);
                                break;
                            }
                        }
                }
            }
        return ans;
    }
    bool dfs(STATUS &cur, int depth, int h, char preDir)
    {
        if(memcmp(&cur, &end, sizeof(STATUS)) == 0 )
        { // OK找到解了:)
            path[depth] = '/0';
            return true;
        }
        if( depth + h > maxDepth ) return false; // 剪枝
        STATUS nxt; // 下一状态
        for(int i=0; i<4; i++)
        {
            if(dirCode[i]==preDir) continue; // 回到上次状态,剪枝
            nxt = cur;
            nxt.r = cur.r + dir[i][0];
            nxt.c = cur.c + dir[i][1];
            if( !( nxt.r >= 0 && nxt.r < 3 && nxt.c >= 0 && nxt.c < 3 ) )
                continue;
            int nxth = h;
            int preLen,Len,desNum=cur.arr[nxt.r][nxt.c],desR=(desNum-1)/3,desC=(desNum-1)%3;
            preLen=abs(nxt.r-desR)+abs(nxt.c-desC);
            Len=abs(cur.r-desR)+abs(cur.c-desC);
            nxth = h - preLen + Len;
            swap(nxt.arr[cur.r][cur.c], nxt.arr[nxt.r][nxt.c]);
            path[depth] = dirCode[i];
            if(dfs(nxt, depth + 1, nxth, rDirCode[i]))
                return true;
        }
        return false;
    }
    int IDAstar()
    {
        int nh = diff(begin);
        maxDepth = nh;
        while (!dfs(begin, 0, nh, '/0'))
            maxDepth++;
        return maxDepth;
    }
    void Input()
    {
        char ch;
        int i, j;
        for(i=0; i < 3; i++){
            for(j=0; j < 3; j++){
                do{
                    scanf("%c", &ch);
                }
                while( !( ( ch >= '1' && ch <= '8' ) || ( ch == 'x' ) ) ) 
                    ;
                if( ch == 'x' ) {
                    begin.arr[i][j] = 0;
                    begin.r = i;
                    begin.c = j;
                }
                else
                    begin.arr[i][j] = ch - '0';
            }
        }
    }
    bool IsSolvable(const STATUS &cur)
    {
        int i, j, k=0, s = 0;
        int a[8];
        for(i=0; i < 3; i++){
            for(j=0; j < 3; j++){
                if(cur.arr[i][j]==0) continue;
                a[k++] = cur.arr[i][j];
            }
        }
        for(i=0; i < 8; i++){
            for(j=i+1; j < 8; j++){
                if(a[j] < a[i])
                    s++;
            }
        }
        return (s%2 == 0);
    }
    int main()
    {
        Input();
        if(IsSolvable(begin)){
            IDAstar();
            printf("%s/n", path);
        }
        else
            printf("unsolvable/n");
        return 0;
    }
  • 相关阅读:
    Laravel 中使用 swoole 项目实战开发案例二 (后端主动分场景给界面推送消息)
    开发 Laravel 扩展的基本流程
    Swoole高效跟传统的web开发有什么区别?
    给各位PHP程序员十点未来的建议
    Swoole 是 PHP 中的 Node.js?
    Laravel 中使用 swoole 项目实战开发案例一 (建立 swoole 和前端通信)
    如何提高 PHP 代码的质量?第三:端到端 / 集成测试
    Java实现 LeetCode 811 子域名访问计数 (暴力)
    Java实现 LeetCode 810 黑板异或游戏 (分析)
    Java实现 LeetCode 810 黑板异或游戏 (分析)
  • 原文地址:https://www.cnblogs.com/hyfer/p/5812534.html
Copyright © 2011-2022 走看看