OpenJ_Bailian - 1077 :Eight (八数码)

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

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.

Sample Input

 2  3  4  1  5  x  7  6  8 

Sample Output

ullddrurdllurdruldr
#include <iostream>
#include <bitset>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <set>
using namespace std;
int goalStatus = 123456780; //目标状态

const int MAXS = 400000; char result[MAXS];   //要输出的移动方案
struct Node {
    int status; //状态
    int father; //父节点指针,即myQueue的下标
    char move;   //父节点到本节点的移动方式 u/d/r/l
    Node(int s,int f,char m):status(s), father(f),move(m) { } Node() { }
};
Node myQueue[MAXS];  //状态队列,状态总数362880
int qHead = 0; //队头指针
int qTail = 1;  //队尾指针
char moves[] = "udrl"; //四种移动

int NewStatus( int status, char move) {
    //求从status经过 move 移动后得到的新状态。若移动不可行则返回-1
    char tmp[20];
    int zeroPos; //字符'0'的位置
    sprintf(tmp,"%09d",status); //需要保留前导0
    for( int i = 0;i < 9; ++ i )
        if( tmp[i] == '0' ) {
            zeroPos = i;
            break;
        } //返回空格的位置
    switch( move) {
        case 'u':
            if( zeroPos - 3 < 0 )
                return -1; //空格在第一行
            else {
                tmp[zeroPos] = tmp[zeroPos - 3];
                tmp[zeroPos - 3] = '0';
            }
            break;

        case 'd':
            if( zeroPos + 3 > 8 )
                return -1; //空格在第三行
            else {
                tmp[zeroPos] = tmp[zeroPos + 3];
                tmp[zeroPos + 3] = '0';
            }
            break;
        case 'l':
            if( zeroPos % 3 == 0)
                return -1; //空格在第一列
            else {
                tmp[zeroPos] = tmp[zeroPos -1];
                tmp[zeroPos -1 ] = '0';
            }
            break;

        case 'r':
            if( zeroPos % 3 == 2)
                return -1; //空格在第三列
            else {
                tmp[zeroPos] = tmp[zeroPos + 1];
                tmp[zeroPos + 1 ] = '0';
            }
            break;
    }
    return atoi(tmp);
}

bool Bfs(int status) {
    //寻找从初始状态status到目标的路径,找不到则返回false
    int newStatus;
    set<int> expanded;
    myQueue[qHead] = Node(status,-1,0);
    expanded.insert(status);
    while ( qHead != qTail) { //队列不为空 
        status = myQueue[qHead].status; 
        if( status == goalStatus ) //找到目标状态 
            return true; 
        for( int i = 0;i < 4;i ++ ) { //尝试4种移动 
            newStatus = NewStatus(status,moves[i]); 
            if( newStatus == -1 )   
                continue; //不可移,试下一种 
            if(expanded.find(newStatus)!=expanded.end()) 
                continue; //已扩展过,试下一种 
            expanded.insert(newStatus);

            myQueue[qTail++] = Node(newStatus,qHead,moves[i]); //新节点入队列
        } 
        qHead ++;
    } 
    return false;
}

int main(){ 
    char line1[50];  
    char line2[20]; 
    while( cin.getline(line1,48)) { 
        int i,j; 
        //将输入的原始字符串变为数字字符串 
        for( i = 0, j = 0; line1[i]; i ++ ) { 
            if( line1[i] != ' ' ) { 
                if( line1[i] == 'x' )  
                    line2[j++] = '0'; 
                else  
                    line2[j++] = line1[i]; 
            } 
        } 
        line2[j] = 0; //字符串形式的初始状态

        if( Bfs(atoi(line2))) { 
            int moves = 0; 
            int pos = qHead; 
            do {  //通过father找到成功的状态序列,输出相应步骤 
                result[moves++] = myQueue[pos].move; 
                pos = myQueue[pos].father; 
            } while( pos); //pos = 0 说明已经回退到初始状态了 
            for( int i = moves -1; i >= 0; i -- ) 
                cout << result[i]; 
            } 
            else 
                cout << "unsolvable" << endl;
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

朱事顺利、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值