HDU 1043 Eight

Posted bzmdAndy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 1043 Eight相关的知识,希望对你有一定的参考价值。

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 22222    Accepted Submission(s): 5963
Special Judge


Problem Description
The 15-puzzle has been around for over 100 years; even if you don‘t know it by that name, you‘ve seen it. It is constructed with 15 sliding tiles, each with a number from 1 to 15 on it, and all packed into a 4 by 4 frame with one tile missing. Let‘s call the missing tile ‘x‘; the object of the puzzle is to arrange the tiles so that they are ordered as:

1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 x

where the only legal operation is to exchange ‘x‘ with one of the tiles with which it shares an edge. As an example, the following sequence of moves solves a slightly scrambled puzzle:

1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4
5 6 7 8 5 6 7 8 5 6 7 8 5 6 7 8
9 x 10 12 9 10 x 12 9 10 11 12 9 10 11 12
13 14 11 15 13 14 11 15 13 14 x 15 13 14 15 x
r-> d-> r->

The letters in the previous row indicate which neighbor of the ‘x‘ tile is swapped with the ‘x‘ tile at each step; legal values are ‘r‘,‘l‘,‘u‘ and ‘d‘, for right, left, up, and down, respectively.

Not all puzzles can be solved; in 1870, a man named Sam Loyd was famous for distributing an unsolvable version of the puzzle, and
frustrating many people. In fact, all you have to do to make a regular puzzle into an unsolvable one is to swap two tiles (not counting the missing ‘x‘ tile, of course).

In this problem, you will write a program for solving the less well-known 8-puzzle, composed of tiles on a three by three
arrangement.
 

 

Input
You will receive, several descriptions of configuration of the 8 puzzle. One description is just a list of the tiles in their initial positions, with the rows listed from top to bottom, and the tiles listed from left to right within a row, where the tiles are represented by numbers 1 to 8, plus ‘x‘. For example, this puzzle

1 2 3
x 4 6
7 5 8

is described by this list:

1 2 3 x 4 6 7 5 8
 

 

Output
You will print to standard output either the word ``unsolvable‘‘, if the puzzle has no solution, or a string consisting entirely of the letters ‘r‘, ‘l‘, ‘u‘ and ‘d‘ that describes a series of moves that produce a solution. The string should include no spaces and start at the beginning of the line. Do not print a blank line between cases.
 

 

Sample Input
2 3 4 1 5 x 7 6 8
 

 

Sample Output
ullddrurdllurdruldr
 

 

Source
 

 

Recommend
JGShining   |   We have carefully selected several similar problems for you:  1044 1026 1072 1010 1180 
题目大意:
给你一个3*3的方格,其中的值为1~8,x,然后你每次能将x与上下左右的四个格子里的元素对调,然后要求将方格里的值调成:
1 2 3
4 5 6
7 8 x
输出怎样变换能够得到(对应的x的l,r,u,p上下左右的移动过程)。对不能完成的情况输出unsolvable。
 
首先这道题我们先思考如何用一个数表示每个棋盘的状态。首先直接把x表示为0。
1.最容易想到的就是变成一个9进制数,但是要表示的数很大,所以并不可行
2.表示成这个数在n!中的排名,表示方法为康托展开。
rk1*(n-1)!+rk2*(n-2)!+...+rkn*0!
rki表示i在i+1..n中的排名
举例312
2*2!+0*1!+0*0!=4
原因其实这个阶段实在计算排列比这个排列字典序更靠前的有多少个,
对于第一位,后面如果有rki个比它小的,就可以知道以这些为开头的都比它小,后面的计算也是如此。
然而复杂度是n^2,这也许就是所谓的时空平衡吧。
然而如果我们在已经知道排名后应该怎么计算原本的排列呢?
有个很像10进制转二进制的想法。
rk1=z/(n-1)! z%=(n-1)!
rk2=z/(n-2)! z%=(n-2)!
...
rkn=z/0! z%=0!
然后就可以根据rk得到原本的序列了(0v0)
 
另一件事,并不是所有的序列都能转化为我们想要的那个,所以需要先进行判断。
而判断的方法是将0移动到与目标相同的0的位置上
然后求对于每一个i,前面比它小的有多少个,如果与目标的奇偶性不同的话,那么输出unsolvable即可
然后开始广搜,要注意判断重复,并且对于每个点记录上一层扩展来的点以便输出方案,然而tle,因为此题是多组数据,所以我们需要进行双向广搜。
过程:
建两个队列,把初始元素放入队列1,把目标元素放入队列2。
然后判断两个队列那一边元素更少,然后选择元素少的那个队列开始扩展。
然后如果新的节点,另一个队列已经走过就可以输出答案了。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=400000;
int x[10],jc[10],to[2][N];
bool yg[10];
struct Z
{
    int z,sg;
    char fx;
}q[2][N];
char bh[2][5]={"udlr","durl"},sr[105];
int has(int *a)
{
    int re=0;
    for(int i=1;i<=9;++i)
    {
        int s=0;
        for(int j=i+1;j<=9;++j)
            if(a[i]>a[j]) ++s;
        re+=s*jc[9-i];
    }
    return re;
}
void nihash(int z)
{
    memset(yg,0,sizeof(yg));
    for(int i=1;i<=9;++i) 
    {
        int rk=z/jc[9-i],k=0;
        z%=jc[9-i];
        for(int j=0;j<=rk;++k)
            if(!yg[k]) ++j;
        yg[x[i]=k-1]=1;
    }
}
int chan(int z,int xh)
{
    nihash(z);
    int wz;
    for(int i=1;i<=9;++i)
        if(!x[i])
        {
            wz=i;
            break;
        }
    switch (xh)
    {
        case 0:if(wz<4) return -1;
               swap(x[wz],x[wz-3]);
               break;
        case 1:if(wz>6) return -1;
               swap(x[wz],x[wz+3]);
               break;
        case 2:if(wz%3==1) return -1;
               swap(x[wz],x[wz-1]);
               break;
        case 3:if(wz%3==0) return -1;
               swap(x[wz],x[wz+1]);
               break;
    }
    return has(x);
}
void print(int a)
{
    if(a==1) return;
    print(q[0][a].sg);
    printf("%c",q[0][a].fx);
}
void bfs()
{
        
    int t[2]={1,1},w[2]={1,1};
    for(;t[0]<=w[0]&&t[1]<=w[1];)
    {
        int xh=w[1]-t[1]<w[0]-t[0];
        for(int i=0;i<4;++i)
        {
            int ns=chan(q[xh][t[xh]].z,i);
            if(ns!=-1&&!to[xh][ns])
            {
                q[xh][++w[xh]]=(Z){ns,t[xh],bh[xh][i]};
                to[xh][ns]=w[xh];
                if(to[!xh][ns])
                {
                    print(to[0][ns]);
                    for(int j=to[1][ns];j>1;j=q[1][j].sg) 
                        printf("%c",q[1][j].fx);
                    return;
                }
            }
        }
        ++t[xh];
    }
}
int main()
{
    jc[0]=1;
    for(int i=1;i<=9;++i) jc[i]=jc[i-1]*i;
    while(cin.getline(sr,100))
    {    
        memset(to,0,sizeof(to));
        int cw,lj=0,len=strlen(sr);
        for(int i=0,j=0;j<9;++i)
            if(sr[i]==x) x[cw=++j]=0;
            else if(sr[i]>=0&&sr[i]<=9) x[++j]=sr[i]-0;
        to[0][q[0][1].z=has(x)]=1;
        if(q[0][1].z==46233) 
        {    
            printf("\n");            
            continue;
        }
        to[1][q[1][1].z=46233]=1;
        while(cw!=9)
        if(cw<7) swap(x[cw],x[cw+3]),cw+=3;
        else swap(x[cw],x[cw+1]),++cw;
        for(int i=2;i<9;++i)
            for(int j=1;j<i;++j)
                if(x[j]<x[i]) ++lj;
        if(lj&1)
        {
            printf("unsolvable\n");
            continue;
        }
        bfs();printf("\n");
    }
    return 0;
}

 

以上是关于HDU 1043 Eight的主要内容,如果未能解决你的问题,请参考以下文章

hdu 1043 Eight(康托展开 + BFS)

HDU 1043 Eight BFS

HDU 1043 Eight

Eight HDU-1043 (bfs)

Hdu 1043 Eight (八数码问题)

HDU1043 Eight