Eight II HDU - 3567
Published on 2018-10-28 01:06 in 分类: 6.2 bfs with zgxme
分类: 6.2 bfs

Eight II HDU - 3567

    Eight II

    Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 130000/65536 K (Java/Others)
    Total Submission(s): 4621    Accepted Submission(s): 1006


    Problem Description
    Eight-puzzle, which is also called "Nine grids", comes from an old game. 

    In this game, you are given a 3 by 3 board and 8 tiles. The tiles are numbered from 1 to 8 and each covers a grid. As you see, there is a blank grid which can be represented as an 'X'. Tiles in grids having a common edge with the blank grid can be moved into that blank grid. This operation leads to an exchange of 'X' with one tile.

    We use the symbol 'r' to represent exchanging 'X' with the tile on its right side, and 'l' for the left side, 'u' for the one above it, 'd' for the one below it.



    A state of the board can be represented by a string S using the rule showed below.



    The problem is to operate an operation list of 'r', 'u', 'l', 'd' to turn the state of the board from state A to state B. You are required to find the result which meets the following constrains:
    1. It is of minimum length among all possible solutions.
    2. It is the lexicographically smallest one of all solutions of minimum length.
     

     

    Input
    The first line is T (T <= 200), which means the number of test cases of this problem.

    The input of each test case consists of two lines with state A occupying the first line and state B on the second line.
    It is guaranteed that there is an available solution from state A to B.
     

     

    Output
    For each test case two lines are expected.

    The first line is in the format of "Case x: d", in which x is the case number counted from one, d is the minimum length of operation list you need to turn A to B.
    S is the operation list meeting the constraints and it should be showed on the second line.
     

     

    Sample Input
    2 12X453786 12345678X 564178X23 7568X4123
     

     

    Sample Output
    Case 1: 2 dd Case 2: 8 urrulldr
     

     

    Author
    zhymaoiing
     

     

    Source
     

     

    Recommend
    zhouzeyong
    题意:就是给起始八位码状态和结束八位码状态 求所需移动最少步数和操作步骤(以最小字典序)
     
    这题卡了好久好久!!o(╥﹏╥)o ,看了大佬们的题解,才做出来的~
    思路:这题结合康拓展开,映射,bfs打表就可以出来了
    比如
    起始状态12X453786  (120453786) 就可以替换为 120345678
     
    映射关系
     
    1 → 1
    2 → 2
    0 → 0
    4 → 3
    5 → 4
    3 → 5
    7 → 6
    8 → 7
    6 → 8
    结束状态12345678X (12345678X) 就可以替换为 125348670
    所以可以先将九种起始状态bfs打表
     
    然后以结束状态八位码状态的康拓展开就可以得到我们想到的了~
     

    康拓展开  %orz

    康托展开是一个全排列到一个自然数双射,常用于构建哈希表时的空间压缩。 康托展开的实质是计算当前排列在所有由小到大全排列中的顺序,因此是可逆的。

    以下称第x个全排列是都是指由小到大的顺序。

    康拓展开式

          X=an(n1)!+an1(n2)!+a10!

     

    例如,3 5 7 4 1 2 9 6 8 展开为 98884。因为X=2*8!+3*7!+4*6!+2*5!+0*4!+0*3!+2*2!+0*1!+0*0!=98884.

    解释:

    排列的第一位是3,比3小的数有两个,以这样的数开始的排列有8!个,因此第一项为2*8!

    排列的第二位是5,比5小的数有1、2、3、4,由于3已经出现,因此共有3个比5小的数,这样的排列有7!个,因此第二项为3*7!

    以此类推,直至0*0!

     

    用途

    显然,n位(0~n-1)全排列后,其康托展开唯一且最大约为n!,因此可以由更小的空间来储存这些排列。由公式可将X逆推出唯一的一个排列。

     

    code  

    复制代码
    static const int FAC[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};   // 阶乘
    int cantor(int *a, int n)
    {
        int x = 0;
        for (int i = 0; i < n; ++i) {
            int smaller = 0;  // 在当前位之后小于其的个数
            for (int j = i + 1; j < n; ++j) {
                if (a[j] < a[i])
                    smaller++;
            }
            x += FAC[n - i - 1] * smaller; // 康托展开累加
        }
        return x;  // 康托展开值
    }
    复制代码

     

     
     
     
    accode 
    复制代码
    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<sstream>
    #include<cstring>
    #include<string>
    #include<vector>
    #include<set>
    #include<stack>
    #include<queue>
    #include<map>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    #define inf 0x3f3f3f3f
    #define ll long long
    #define MAX_N 362882 + 10
    #define gcd(a,b) __gcd(a,b)
    #define mem(a,x) memset(a,x,sizeof(a))
    #define mid(a,b) a+b/2
    #define stol(a) atoi(a.c_str())//string to long
    int fac[10];
    int beg[10][10] ={{0, 1, 2, 3, 4, 5, 6, 7, 8},{1, 0, 2, 3, 4, 5, 6, 7, 8},{1, 2, 0, 3, 4, 5, 6, 7, 8},{1, 2, 3, 0, 4, 5, 6, 7, 8},{1, 2, 3, 4, 0, 5, 6, 7, 8},{1, 2, 3, 4, 5, 0, 6, 7, 8},{1, 2, 3, 4, 5, 6, 0, 7, 8},{1, 2, 3, 4, 5, 6, 7, 0, 8},{1, 2, 3, 4, 5, 6, 7, 8, 0}};
    int dir[5][2] = {{1,0},{0,-1},{0,1},{-1,0}};
    char operate[5] = "dlru";
    int c;
    int cal_cantor(int a[]){
        int ans = 0;
        for (int i = 0; i < 9; i++){
            int temp = 0;
            for (int j = i + 1; j < 9; j++){
                if (a[j] < a[i]){
                    temp++;
                }
            }
            ans += temp * fac[8 - i];
        }
        return ans;
    }
    int temp[10];
    int mark[10];
    int start_cantor[10];
    struct Node{
        int a[10];
        int x;
    };
    struct Vis{
        int pre;
        char p;
        int step;
    }vis[10][MAX_N];
    
    void bfs(int t,Node node){
        queue<Node> que;
        que.push(node);
        while(que.size()){
            Node n = que.front();
            que.pop();
            int n_contor = cal_cantor(n.a);
            int pos = n.x;
            for(int i = 0; i < 4; i++){
                int x = n.x/3;
                int y = n.x%3;
                int nx = x + dir[i][0];
                int ny = y + dir[i][1];
                if(nx >= 0 && nx < 3 && ny >= 0 && ny < 3){
                    int cnt = nx * 3 + ny;
                    swap(n.a[cnt],n.a[pos]);
                    n.x = cnt;
                    int v = cal_cantor(n.a);
                    if(vis[t][v].pre == -1&&v!=start_cantor[t]){
                        vis[t][v].pre = n_contor;
                        vis[t][v].p = operate[i];
                        vis[t][v].step = vis[t][n_contor].step + 1;
                        que.push(n);
                    }
                    n.x = pos;//
                    swap(n.a[cnt],n.a[pos]);
                }
    
            }
    
        }
    }
    
    void init(){
        fac[0] = fac[1] = 1;
        for (int i = 2; i < 10; i++){
            fac[i] = fac[i - 1] * i;
        }
        for(int i = 0; i < 9; i++){
            for(int j = 0; j < MAX_N;j++)
                vis[i][j].pre = -1;
        }
        Node node;
        for(int i = 0; i < 9; i++){
            swap(node.a,beg[i]);
            node.x = i;
            start_cantor[i] = cal_cantor(node.a);
            bfs(i,node);
            swap(node.a,beg[i]);
        }
    }
    int main(){
        //std::ios::sync_with_stdio(false);
        //std::cin.tie(0);
        #ifndef ONLINE_JUDGE
            freopen("D:\\in.txt","r",stdin);
            freopen("D:\\out.txt","w",stdout);
        #else
        #endif
        init();
        int T;
        scanf("%d",&T);
        string str;
        int t = 0;
        while(T--){
            cin >> str;
            for(int i = 0; i < 9; ++i){
                temp[i] = (str[i] == 'X'? 0 : str[i]-'0');
                if(str[i] == 'X')
                    c = i;
            }
            for(int i = 0; i < 9; ++i){
                mark[temp[i]] = beg[c][i];
            }
            cin >> str;
            for(int i = 0; i < 9; ++i){
                temp[i] = (str[i] == 'X'? 0 : str[i]-'0');
                temp[i] = mark[temp[i]];
            }
            Node n;
            swap(n.a,temp);
            int end_ = cal_cantor(n.a);
            printf("Case %d: %d\n",++t,vis[c][end_].step);
            string ans = "";
            while(vis[c][end_].step!=0){
                ans = vis[c][end_].p + ans;
                end_ = vis[c][end_].pre;
            }
            cout<<ans<<endl;
    
        }
    
        return 0;
    }
    复制代码

     

     
    posted @   zgxme  阅读(272)  评论(0编辑  收藏  举报
    编辑推荐:
    · 没有源码,如何修改代码逻辑?
    · 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
    · [.NET]调用本地 Deepseek 模型
    · 一个费力不讨好的项目,让我损失了近一半的绩效!
    · .NET Core 托管堆内存泄露/CPU异常的常见思路
    阅读排行:
    · DeepSeek “源神”启动!「GitHub 热点速览」
    · 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
    · C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
    · DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
    · NetPad:一个.NET开源、跨平台的C#编辑器
    点击右上角即可分享
    微信分享提示