HDU 1043 Eight

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

八数码问题,给出一个3x3的棋盘,上有1~8 共8个棋子,x表示空格,问是否能将棋子顺序还原为12345678x

棋盘中只包含数字1~8和x,把x记为0,最终要还原成123456780,输入的棋盘可看成是 0 ~ 8 这9个数的全排列 中的一种排列,要判断输入的棋盘是否可以还原成123456780,现可以反向解答,以123456780为初始状态,0向4个方向走,看是否会出现输入的状态,若能,则可以还原,否则不可还原。

运用康托展开:康托展开满足双射的关系,可以根据当前的排列求出它是全排列中的第几个

#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN = 362880 + 7; // 876543210 的hash值为362880,即最大只会达到362880
static const int FAC[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};    // 阶乘
int dir[4][2] = {1, 0, -1, 0, 0, 1, 0, -1};
char op[] = "udlr"; // 因为是反向bfs,所以这里与dir的方向是相反的。
int result = 46234; // 123456780 的hash值为46234, 
int tmp[9]; // 把3x3的图存成1维的
int vis[MAXN];
string path[MAXN];
// 康托展开
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 += smaller * FAC[9 - i - 1];
    }
    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];
        v.erase(v.begin() + t);
    }
}
struct node
{
    string path;
    int hashs;
    int pos;
}now, nxt;
void bfs()
{
    queue<node> q;
    memset(vis, 0, sizeof(vis));
    for(int i = 0; i < 8; i++) // (最终目标是123456780)tmp初始为123456780,从这里开始反向bfs
        tmp[i] = i + 1;
    tmp[8] = 0;
    now.path = "";
    now.hashs = result;
    now.pos = 8;
    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 + dir[i][0];
            int ty = now.pos % 3 + dir[i][1];
            if(tx >= 0 && tx < 3 && ty >= 0 && ty < 3)
            {
                nxt = now;
                nxt.pos = tx * 3 + ty;
                decantor(now.hashs - 1, tmp); // 求上一步的tmp
                swap(tmp[now.pos], tmp[nxt.pos]); // 移动x的位置
                nxt.hashs = cantor(tmp);  // 得到新的tmp
                if(!vis[nxt.hashs])
                {
                    vis[nxt.hashs] = 1;
                    nxt.path = op[i] + nxt.path;
                    q.push(nxt);
                    path[nxt.hashs] = nxt.path;
                }
            }
        }
    }
}
int main()
{
    bfs();

    string str;
    while(getline(cin, str))
    {
        stringstream s(str);
        char x;
        int tt = 0;
        while(s >> x)
        {
            if(x == 'x')
                tmp[tt++] = 0;
            else
                tmp[tt++] = x - '0';
        }
        int hashs = cantor(tmp);
        if(!vis[hashs])
            cout << "unsolvable" << endl;
        else
            cout << path[hashs] << endl;
    }
    return 0;
}

你可能感兴趣的:(搜索,#,专题二,搜索进阶,【kuangbin带你飞】)