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


    题目描述:

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

     

    中文大意:

    给定八数码的初始状态和目标状态,要求输出移动过程。

    最终输出的移动过程需要是所有解决方案中长度最短、字典序最小的。

    思路:

    采用打表的方式来做这道题。

    但八数码问题一共有 9! 种状态,以每种状态为广搜起点并记录到达剩余状态的移动信息,工作量太大。

    需要将八数码问题抽象成九种初始状态:

    012345678

    102345678

    120345678

    123045678

    123405678

    123450678

    123456078

    123456708

    123456780

    例如,初始状态 120453786 和目标状态 123456780,

    对应初始状态 120345678 和目标状态 125348670。

    状态 120345678 到状态 125348670 的移动过程我们已经知道,按要求输出即可。

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

    paths[k][i] 中的 k :9 种初始状态,

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

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

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

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

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

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

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

     

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    
    struct node{
        int state[9];
        int pos;
    };
    
    int start[9];
    int goal[9];
    
    int factory[] = {1,1,2,6,24,120,720,5040,40320,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;
    }
    
    bool visited[362880];
    
    int dir[4][2] = {{0,1}, {-1,0}, {1,0}, {0,-1}};
    char dirs[4] = {'d', 'l', 'r', 'u'};
    
    struct path{
        int from;
        char dir;
    }paths[9][362880];
    
    void a_start(int k){
        node head,next;
        
        memcpy(head.state, start, sizeof(start));
        head.pos = k;
        
        memset(visited, false, sizeof(visited));
        int h_cantor = Cantor(head.state, 9);
        visited[h_cantor] = true;
        paths[k][h_cantor].from = -1;
           
        queue<node> q;
        q.push(head);
        
        while(!q.empty()){
            head = q.front();
            q.pop();
            
            h_cantor = Cantor(head.state, 9);
            for(int i=0;i<4;i++){
                int x = head.pos % 3;
                int y = head.pos / 3;
                
                int nx = x + dir[i][0];
                int ny = y + 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]);
                    
                    int n_cantor = Cantor(next.state, 9);
                    if(!visited[n_cantor]){
                        visited[n_cantor] = true;
                        
                        paths[k][n_cantor].from = h_cantor;
                        paths[k][n_cantor].dir = dirs[i];
                        
                        q.push(next);
                    }
                }
            }
        }
    }
    
    void new_start(int k){
        int t = 1;
        for(int i=0;i<9;i++){
            if(i == k){
                start[i] = 0;
            }
            else{
                start[i] = t;
                t++;
            }
        }
    }
    
    int main(){
        for(int i=0;i<9;i++){
            new_start(i);
            a_start(i);
        }
        
        int num;
        scanf("%d", &num);
        for(int i=1;i<=num;i++){
            char str[9];
            scanf("%s", str);
            
            int maps[9];
            int k,t = 1; 
            for(int j=0;j<9;j++){
                int num = str[j] - '0';
                if(num > 9){
                    k = j;
                    num = 0;
                    maps[num] = 0;
                }
                else{
                    maps[num] = t;
                    t++;
                }
            }
            
            scanf("%s", str);
            for(int j=0;j<9;j++){
                int num = str[j] - '0';
                if(num > 9){
                    num = 0;
                }
                
                goal[j] = maps[num];
            }
            
            string result;
            int cantor = Cantor(goal, 9);
            while(paths[k][cantor].from != -1){
                result = paths[k][cantor].dir + result;
                cantor = paths[k][cantor].from;
            }
            
            printf("Case %d: %d
    ", i, result.length());
            cout<<result<<endl;
        }
    }
    作者:老干妈就泡面
    本文版权归作者和博客园共有,欢迎转载,但请给出原文链接,并保留此段声明,否则保留追究法律责任的权利。
  • 相关阅读:
    NLP---word2vec的python实现
    matplotlib---Annotation标注
    matplotlib---legend图例
    matplotlib---设置坐标轴
    windows下右键新建md文件
    vue+webpack+npm 环境内存溢出解决办法
    element-ui tree树形组件自定义实现可展开选择表格
    vue-动态验证码
    ES6 数组函数forEach()、map()、filter()、find()、every()、some()、reduce()
    eslint配置文件规则
  • 原文地址:https://www.cnblogs.com/bjxqmy/p/14416241.html
Copyright © 2020-2023  润新知