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 1213 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 1213 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

South Central USA 1998 (Sepcial Judge Module By JGShining)

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;
}
时间: 2024-09-28 21:39:35

HDU 1043 Eight的相关文章

HDU 1043 POJ 1077 八数码问题

以下内容转载自:http://www.cnblogs.com/goodness/archive/2010/05/04/1727141.html 八数码的八境界 研究经典问题,空说不好,我们拿出一个实际的题目来演绎.八数码问题在北大在线测评系统中有一个对应的题,题目描述如下: Eight Time Limit: 1000MS    Memory Limit: 65536K  Special Judge Description The 15-puzzle has been aroundfor ove

HDU 1043 Eight(八数码)

p.MsoNormal { margin: 0pt; margin-bottom: .0001pt; text-align: justify; font-family: Calibri; font-size: 10.5000pt } h1 { margin-top: 5.0000pt; margin-bottom: 5.0000pt; text-align: center; font-family: 宋体; color: rgb(26,92,200); font-weight: bold; fo

HDU - 1043 - Eight / POJ - 1077 - Eight

先上题目: Eight Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 11243    Accepted Submission(s): 3022Special Judge Problem Description The 15-puzzle has been around for over 100 years; even if you

HDU 1043 Eight(反向BFS+打表+康托展开)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1043 题目大意:传统八数码问题 解题思路:就是从“12345678x”这个终点状态开始反向BFS,将各个状态记录下来,因为数字太大所以用康托展开将数字离散化. 代码: 1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<cstring> 5 #include<st

HDU 1043 Eight(双向BFS+康托展开)

http://acm.hdu.edu.cn/showproblem.php?pid=1043 题意:给出一个八数码,求出到达指定状态的路径. 思路:路径寻找问题.在这道题里用到的知识点挺多的.第一次用双向BFS来做. ①双向BFS 在单向BFS的基础上,多建一个从终止状态开始搜索的队列,当然这个时候需要两个vis[]辅助数组,分别记录两个队列的访问情况,当两个队列相遇时即可终止循环. ②康托展开 X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[

Hdu 1043 Eight (八数码问题)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1043 题目描述: 3*3的格子,填有1到8,8个数字,还有一个x,x可以上下左右移动,问最终能否移动到12345678x的状态? hint:每一个3*3的格子从上到右,从左到右,一行一行读. 解题思路: 比较简单的八数码问题,大一暑假老师讲过,一直手懒脑懒并没有亲自尝试过.因为是多实例,先从12345678x的状态bfs出来所有可以到达的状态,并且记录下来路径.八数码最重要的就是保存状态,如果这个

HDU 1043 Eight八数码解题思路(bfs+hash 打表 IDA* 等)

题目链接 https://vjudge.net/problem/HDU-1043 经典的八数码问题,学过算法的老哥都会拿它练搜索 题意: 给出每行一组的数据,每组数据代表3*3的八数码表,要求程序复原为初始状态 思路: 参加网站比赛时拿到此题目,因为之前写过八数码问题,心中暗喜,于是写出一套暴力bfs+hash,结果TLE呵呵 思路一:bfs+hash(TLE) 1 #include <cstdio> 2 #include <cstring> 3 #include <queu

Eight hdu 1043 poj 1077

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 mis

HDU 1043 八数码(八境界)

8境界:http://www.cnblogs.com/goodness/archive/2010/05/04/1727141.html 境界一. 暴力广搜+STL (HDU 内存超限,POJ 时间超限) map存路径,set判重,string存状态,毫无疑问,炸了. #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<vector> #inclu