【HDU - 1043】Eight(反向bfs+康托展開)


Eight

Descriptions:

簡單介紹一下八數碼問題:
在一個3×3的九宮格上,填有1~8八個數字,空余一個位置,例如下圖:

1 2 3
4 5 6
7 8  

在上圖中,由於右下角位置是空的,你可以移動數字,比如可以將數字6下移一位:

1 2 3   1 2 3
4 5 6 4 5  
7 8     7 8 6

或者將數字8右移一位:

1 2 3   1 2 3
4 5 6 4 5 6
7 8     7   8

1~8按順序排列的情況稱為“初始狀態”(如最上方圖)。“八數碼問題”即是求解對於任意的布局,將其移動至“初始狀態”的方法。 
給定一個現有的九宮格布局,請輸出將它移動至初始狀態的移動方法的步驟。
Input

輸入包含多組數據,處理至文件結束。每組數據占一行,包含8個數字和表示空位的‘x’,各項以空格分隔,表示給定的九宮格布局。 
例如,對於九宮格

1 2 3
  4 6
7 5 8

輸入應為:1 2 3 x 4 6 7 5 8

Output

對於每組輸入數據,輸出一行,即移動的步驟。向上、下、左、右移動分別用字母u、d、l、r表示;如果給定的布局無法移動至“初始 狀態”,請輸出unsolvable。
如果有效的移動步驟有多種,輸出任意即可。

Sample Input

2  3  4  1  5  x  7  6  8

Sample Output

ullddrurdllurdruldr

題目鏈接

https://vjudge.net/problem/HDU-1043

 

其實就是反向bfs,不過用了一個新的方法去存放拼圖序列,康托展開即把拼圖(x12345678)全排列,再用數字去表示,簡而言之就是用不同的數字去代替拼圖序列,使之跟簡單、快速的搜索

不會康托展開不關系,點擊下面鏈接,現學現會

https://www.cnblogs.com/sky-stars/p/11216035.html

 

AC代碼

#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
#include <sstream>
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
#define Mod 1000000007
#define eps 1e-6
#define ll long long
#define INF 0x3f3f3f3f
#define MEM(x,y) memset(x,y,sizeof(x))
#define Maxn 362880+5//876543210的hash值為362880 即最多出現362880種可能
using namespace std;
static const int FAC[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};    // 階乘
struct node
{
    string path;//路徑
    int hashs;//hash值
    int pos;//0的位置
};
node now,net;
queue<node>q;
int dt[][4]= {{1,0},{-1,0},{0,1},{0,-1}};//四個方向
char op[5]="udlr";//這個與上面的搜索方向是反的,因為是反向bfs
int tmp[9];//臨時存儲拼圖的序列
int result=46234;//123456780    最終答案的hash值
string path[Maxn];//path[x] hash值為x的路徑
int vis[Maxn];//vis[x]  hash值為x的拼圖序列是否標記過
//康托展開
int cantor(int *a)
{
    int x = 0;
    for (int i = 0; i < 9; ++i)
    {
        int smaller = 0;  // 在當前位之后小於其的個數
        for (int j = i + 1; j < 9; ++j)
        {
            if (a[j] < a[i])
                smaller++;
        }
        x += FAC[9 - i - 1] * smaller; // 康托展開累加
    }
    return x+1;  // 康托展開值
}
//逆康托展開
void decantor(int x, int *a)
{
    vector<int> v;  // 存放當前可選數
    for(int i=0; i<9; i++)
        v.push_back(i);
    for(int i=0; i<9; i++)
    {
        int r = x % FAC[9-i-1];
        int t = x / FAC[9-i-1];
        x = r;
        sort(v.begin(),v.end());// 從小到大排序
        a[i]=v[t];      // 剩余數里第t+1個數為當前位
        v.erase(v.begin()+t);   // 移除選做當前位的數
    }
}
void bfs()
{
    MEM(vis,0);//初始化
    for(int i=0; i<8; i++)//tmp一開始為123456780,從這開始打散拼圖
        tmp[i]=i+1;
    tmp[8]=0;
    now.pos=8;
    now.hashs=result;
    now.path="";
    path[result]="";
    vis[result]=1;
    q.push(now);
    while(!q.empty())
    {
        now=q.front();
        q.pop();
        for(int i=0; i<4; i++)//四個方向
        {
            int tx=now.pos/3+dt[i][0];
            int ty=now.pos%3+dt[i][1];
            if(tx>=0&&ty>=0&&tx<=2&&ty<=2)//沒走出去拼圖
            {
                net=now;
                net.pos=tx*3+ty;
                decantor(now.hashs-1,tmp);//求tmp
                swap(tmp[now.pos],tmp[net.pos]);//得到新的tmp
                net.hashs=cantor(tmp);//得到新tmp對應的hash
                if(!vis[net.hashs])//這都bfs老套路了 沒啥說的
                {
                    vis[net.hashs]=1;
                    net.path=op[i]+net.path;
                    q.push(net);
                    path[net.hashs]=net.path;
                }
            }
        }
    }
    return;
}
int main()
{
    bfs();
    char x;
    while(cin>>x)//輸入格式 沒啥說的
    {
        if(x=='x')
        {
            now.pos=0;
            tmp[0]=0;
        }
        else
        {
            tmp[0]=x-'0';
        }
        for(int i=1; i<9; i++)
        {
            cin>>x;
            if(x=='x')
            {
                now.pos=i;
                tmp[i]=0;
            }
            else
            {
                tmp[i]=x-'0';
            }
        }
        now.hashs=cantor(tmp);//求出tmp這個拼圖序列的hash值
        if(!vis[now.hashs])//這個hash沒標記過,即沒產生過這個拼圖序列
            cout<<"unsolvable"<<endl;
        else
            cout<<path[now.hashs]<<endl;//輸出hash的路徑
    }
    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM