poj 1077 eight

/*
C:Eight
查看 提交 统计 提问
总时间限制: 5000ms 内存限制: 65536kB
描述
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.
输入
You will receive a description of a configuration of the 8 puzzle. The 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
输出
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.
样例输入
 2  3  4  1  5  x  7  6  8
样例输出
ullddrurdllurdruldr
*/

#include <cstdio>
#include <list>
#include <queue>
#include <vector>
#include <string>
#include <cstring>
#include <iostream>
using namespace std;

bool vsi[9][9][9][9][9][9][9][9] = {0};
int dx[5] = {-1, 0, 1, 0}, dy[5] = {0, 1, 0, -1};
char dir[5] = {'u', 'r', 'd', 'l'};
struct square
{
    short num[3][3];
    int zx;
    int zy;
    string move;
};

square end;

list <square> lst;

bool visited(square sq)
{
    if(vsi[sq.num[0][0]][sq.num[0][1]][sq.num[0][2]][sq.num[1][0]][sq.num[1][1]][sq.num[1][2]][sq.num[2][0]][sq.num[2][1]] == 1)
    return 1;
    else return 0;
}

void visit(square sq)
{
    vsi[sq.num[0][0]][sq.num[0][1]][sq.num[0][2]][sq.num[1][0]][sq.num[1][1]][sq.num[1][2]][sq.num[2][0]][sq.num[2][1]] = 1;
    return;
}

void bfs(square s)
{
    if(visited(end)) return;
    for(int i = 0; i < 4; ++i)
    {
        if(s.zx + dx[i] >= 0 && s.zx + dx[i] < 3 && s.zy + dy[i] >= 0 && s.zy + dy[i] < 3)
        {
            square tep;
            /**/for(int j = 0; j < 3; ++j)
            for(int k = 0; k < 3; ++k)
            tep.num[j][k] = s.num[j][k];
            tep.zx = s.zx;
            tep.zy = s.zy;
            tep.move.assign(s.move);
            tep.num[s.zx][s.zy] = s.num[s.zx + dx[i]][s.zy + dy[i]];
            tep.num[s.zx + dx[i]][s.zy + dy[i]] = s.num[s.zx][s.zy];
            tep.zx = s.zx + dx[i];
            tep.zy = s.zy + dy[i];
            if(visited(tep)) continue;
            if(visited(end)) break;
            visit(tep);
            tep.move.append(1,dir[i]);
            if(visited(end))
            {
                end.move.assign(tep.move);
                break;
            }
            lst.push_back(tep);
        }
    }
    return;
}

int main()
{
    square start;
    char t;
    for(int i = 0; i < 9; ++i)
    {
        cin >> t;
        if(i != 8) end.num[i/3][i%3] = i + 1;
        if(t == 'x')
        {
            start.num[i / 3][i % 3] = 0;
            start.zx = i / 3;
            start.zy = i % 3;
        }
        else start.num[i / 3][i % 3] = t - '0';
    }
    int m = 0;
    for(int i = 0; i < 3; ++i)
    for(int j = 0; j < 3; ++j)
    if(start.num[i][j] != end.num[i][j]) {m = 1;break;}
    if(m == 0) printf("0\n");
    else
    {
    end.zx = 2;
    end.zy = 2;
    visit(start);
    lst.push_front(start);

    while(!lst.empty())
    {
        bfs(lst.front());
        lst.pop_front();
    }
    if(end.move.length() == 0) cout << "unsolvable" << endl;
    else cout << end.move << endl;

    }
    return 0;
}
//=========================================================================
#include <iostream>
#include <bitset>
using namespace std;
int nGoalStatus;  //目标状态
bitset<387420498> Flags; //节点是否扩展的标记
char szResult[400000];   //结果
char szMoves[400000]; //移动步骤 : u/d/r/l
int anFather[400000]; //父节点指针
int MyQueue[400000];  //状态队列,状态总数362880
int nQHead;
int nQTail;
char sz4Moves[] = "udrl";//四种动作


int NineToTen( char * s )
{


//九进制字符串转十进制


    int nResult = 0;
    for( int i = 0; s[i]; i ++ )
    {
        nResult *= 9;
        nResult += s[i] - '0';
    }
    return nResult;
}
int TenToNine( int n, char * s)
{
//十进制数转九进制字符串。可能有前导0,返回0的位置
    int nZeroPos;
    int nBase = 1;
    int j = 0;
    while( nBase <= n) /*从高位开始的进制转换*/
        nBase *= 9;
    nBase /= 9;
    do
    {
        s[j] = n/nBase + '0';
        if( s[j] == '0' )
            nZeroPos = j;
        j ++;
        n %= nBase;
        nBase /= 9;
    }
    while( nBase >= 1 );
    s[j] = 0;//串结束符
    //判断是否要加前导0,此时第0位即为0
    if( j < 9 )
    {
        for( int i = j + 1; i > 0; i --)
            s[i] = s[i-1];
        s[0] = '0';
        return 0;
    }
    return nZeroPos;
}
int NewStatus( int nStatus, char cMove)
{
//求从nStatus经过 cMove 移动后得到的新状态。若移动不可行则返回-1
    char szTmp[20];
    int nZeroPos = TenToNine(nStatus,szTmp);//返回空格的位置
    switch( cMove)
    {
    case 'u':
        if( nZeroPos - 3 < 0 )  return -1; //空格在第一行
        else
        {
            szTmp[nZeroPos] = szTmp[nZeroPos - 3];
            szTmp[nZeroPos - 3] = '0';
        }
        break;
    case 'd':
        if( nZeroPos + 3 > 8 )  return -1; //空格在第三行
        else
        {
            szTmp[nZeroPos] = szTmp[nZeroPos + 3];
            szTmp[nZeroPos + 3] = '0';
        }
        break;
    case 'l':
        if( nZeroPos % 3 == 0)  return -1; //空格在第一列
        else
        {
            szTmp[nZeroPos] = szTmp[nZeroPos -1];
            szTmp[nZeroPos -1 ] = '0';
        }
        break;
    case 'r':
        if( nZeroPos % 3 == 2)  return -1; //空格在第三列
        else
        {
            szTmp[nZeroPos] = szTmp[nZeroPos + 1];
            szTmp[nZeroPos + 1 ] = '0';
        }
        break;
    }
    return NineToTen(szTmp);
}


bool Bfs(int nStatus)
    {
        int nNewStatus;
        nQHead = 0;
        nQTail = 1;
        MyQueue[nQHead] = nStatus;
        while ( nQHead != nQTail)   //队列不为空
        {
            nStatus = MyQueue[nQHead];
            if( nStatus == nGoalStatus ) //找到目标状态
                return true;
            for( int i = 0; i < 4; i ++ ) //尝试4种移动
            {
                nNewStatus = NewStatus(nStatus,sz4Moves[i]);
                if( nNewStatus == -1 ) 	continue; //不可移,试下一种
                if( Flags[nNewStatus] )
                    continue; //如果扩展标记已经存在,则不能入队
                Flags.set(nNewStatus,true); //设上已扩展标记
                MyQueue[nQTail] = nNewStatus; //新节点入队列
                anFather[nQTail] = nQHead; //记录父节点
                //记录本节点是由父节点经什么动作而来


                szMoves[nQTail] = sz4Moves[i];
                nQTail ++;
            }
            nQHead ++;
        }
        return false;
    }




int main()
{
    char tep[12] = "123456780";
    nGoalStatus = NineToTen(tep);
    Flags.reset();
    char szLine[50];
    char szLine2[20];
    cin.getline(szLine,48);
    int i,j;
    //将输入的原始字符串变为九进制字符串
    for( i = 0, j = 0; szLine[i]; i ++ )
    {
        if( szLine[i] != ' ' )
        {
            if( szLine[i] == 'x' )  szLine2[j++] = '0';
            else  szLine2[j++] = szLine[i];
        }
    }
    szLine2[j] = 0;
    if( Bfs(NineToTen(szLine2)))
    {
        int nMoves = 0;
        int nPos = nQHead;
        do    //通过anFather数组找到成功的状态序列,输出相应步骤
        {
            szResult[nMoves++] = szMoves[nPos];
            nPos = anFather[nPos];
        }
        while( nPos);
        for( int i = nMoves -1; i >= 0; i -- )
            cout << szResult[i];
    }
    else
        cout << "unsolvable" << endl;
    return 0;
}  

你可能感兴趣的:(poj,cpp)