• 【逆向BFS + 康托展开 + 打表】hdu 1043 Eight(八数码问题)


    题目描述:

    http://acm.hdu.edu.cn/showproblem.php?pid=1043

     

    中文大意:

    经典八数码问题。

    给定初始状态,要求变换到目标状态并输出移动过程。

    目标状态固定为:1 2 3 4 5 6 7 8 x 。

     

    思路:

    采用逆向 BFS + 康托展开判重 + 打表的方法来做这道题。

    八数码问题一共有 9! 种状态,每种状态对应一个 cantor 值。

    以目标状态为 BFS 起始状态,搜索这 9! 种状态。

    移动信息记录在 paths[362880] 数组中。

    paths[i] 中的 i :现状态的 cantor 值,

    pahts[i].from :前状态的 cantor 值,

    paths[i].dir :前状态->现状态的移动方向。

    因为是逆向 BFS,所以输出的时候需要反过来,即上对下,左对右。

    队列节点记录的是当前八数码状态和 “x” 的位置。

    在弹出队列首节点,确定了当前八数码的状态信息后,下一步有 4 种选择:“x” 上下左右移动。

    “康托展开”用来计算当前状态的 cantor 值,判断该状态是否已经被访问 visited[cantor]。

    注意:①移动信息不能直接记录在 string 中,否则会超内存限制;

    ②杭电oj 上的这道题有多组数据,需要 while(cin>>temp)。

     

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    
    struct node{
        int state[9];//当前状态 
        int pos;//"x"的位置 
    };
    
    int goal[9];
    int start[9] = {1,2,3,4,5,6,7,8,0};
    
    //上下左右 
    int dir[4][2] = {{0, -1}, {0, 1}, {-1, 0}, {1, 0}};
    //逆向 
    char dir_str[4] = {'d', 'u', 'r', 'l'};
    
    //Cantor用到的常数 
    int factory[] = {1,1,2,6,24,120,720,5040,40320,362880};
    
    bool visited[362880] = {false};
     
    struct node2{
        int from;//前状态 
        int dir;//前状态->现状态的移动方向 
    }paths[362880];
    
    int Cantor(int state[], int n){
        int result = 0;
        for(int i=0;i<n;i++){
            int counted = 0;
            for(int j=i+1;j<n;j++){
                if(state[i] > state[j]){
                    counted++;
                }
            }
            result += counted * factory[n-i-1];
        }
        
        return result;
    }
    
    void bfs(){
        node head,next;
        memcpy(head.state, start, sizeof(start));
        head.pos = 8;
        
        int cantor = Cantor(head.state, 9);
        visited[cantor] = true;
        
        paths[cantor].from = -1;
        
        queue<node> q;
        q.push(head);
        
        while(!q.empty()){
            head = q.front();
            q.pop();
            
            int px = head.pos % 3;
            int py = head.pos / 3;
            
            int head_cantor = Cantor(head.state, 9);
            for(int i=0;i<4;i++){    
                int nx = px + dir[i][0];
                int ny = py + dir[i][1];
                
                if(nx >= 0 && nx < 3 && ny >= 0 && ny < 3){
                    memcpy(next.state, head.state, sizeof(head.state));
                    next.pos = ny * 3 + nx;
                    
                    swap(next.state[next.pos], next.state[head.pos]);
                    
                    cantor = Cantor(next.state, 9);
                    if(!visited[cantor]){
                        visited[cantor] = true;
                                            
                        paths[cantor].from = head_cantor;
                        paths[cantor].dir = i;
                        
                        q.push(next);
                    }
                }
            }
        }
    }
    
    void print(int cantor){
        while (paths[cantor].from != -1){
            printf("%c", dir_str[paths[cantor].dir]);
            cantor = paths[cantor].from;
        }
        printf("
    ");
    }
    
    int main(){
        bfs();
        
        char temp;
        while (cin>>temp){
            goal[0] = temp - '0';
            if(goal[0] > 9){
                goal[0] = 0;
            }
            
            for (int i=1;i<9;i++){
                cin>>temp;
                goal[i] = temp - '0';
                
                if(goal[i] > 9){
                    goal[i] = 0;
                }
            }
            
            int cantor = Cantor(goal, 9);
            if (!visited[cantor]){
                cout << "unsolvable" << endl;
            }
            else{
                print(cantor);
            }
        }
    } 
    作者:老干妈就泡面
    本文版权归作者和博客园共有,欢迎转载,但请给出原文链接,并保留此段声明,否则保留追究法律责任的权利。
  • 相关阅读:
    linux c/c++ 获取文件大小
    android 打开各种文件(setDataAndType)
    Android framework系统默认设置修改
    android的 root权限
    [Power]待机电流问题,如何查找wakelock
    Android.mk for your own module
    通过adb 发送广播
    ubuntu下minicom的安装及使用
    ubuntu 下使用 putty 调试
    Android平台Overlay机制
  • 原文地址:https://www.cnblogs.com/bjxqmy/p/14383845.html
Copyright © 2020-2023  润新知