AOJ-0121

Seven Puzzle

Time Limit : 1 sec, Memory Limit : 65536 KB

Seven Puzzle

7パズルは8つの正方形のカードとこれらのカードがぴたりと収まる枠を使って行います。それぞれのカードは互いに区別できるように、0,1,2....7と番号がつけられています。枠には、縦に2個、横に4個のカードを並べることができます。

7パズルを始めるときには、まず枠にすべてのカードを入れます。枠のなかで0のカードだけは、上下左右に隣接するカードと位置を交換することができます。たとえば、枠の状態が図( a )のときに、0のカードの右に隣接した、7のカードと位置を交換すれば、図( b )の状態になります。あるいは、図( a )の状態から0のカードの下に隣接した2のカードと位置を交換すれば図( c )の状態になります。カードの位置を入れ替える操作はこれだけが許されます。図( a )の状態で0のカードと上下左右に隣接するカードは7と2のカードだけなので、これ以外の位置の入れ替えは許されません。

ゲームの目的は、カードをきれいに整列して図( d )の状態にすることです。最初の状態を入力とし、カードをきれいに整列するまでに、必要な最小手数を出力して終了するプログラムを作成してください。ただし、入力されたカードの状態からは図( d )の状態に移ることは可能であるとします。

入力データは、1行に8つの数字が与えられます。これらは、最初の状態のカードの並びを表します。図( a )の数字表現は0,7,3,4,2,5,1,6に、図( c )は2,7,3,4,0,5,1,6となります。

図( a ) 0,7,3,4,2,5,1,6の場合 図( b ) 7,0,3,4,2,5,1,6の場合


図( c ) 2,7,3,4,0,5,1,6の場合 図( d ) 0,1,2,3,4,5,6,7(最終状態)

Input

1つ目のパズルの状態(整数;空白区切り)
2つ目のパズルの状態(整数;空白区切り)
     :
     :

与えられるパズルの数は1000以下です。

Output

1つ目のパズルの状態から最終状態へ移行する最小手数(整数)
2つ目のパズルの状態から最終状態へ移行する最小手数(整数)
            :
            :

Sample Input

0 1 2 3 4 5 6 7
1 0 2 3 4 5 6 7
7 6 5 4 3 2 1 0

Output for the Sample Input

0
1
28
题意:7数码问题。在2×4的棋盘上,摆有8个棋子,每个棋子上标有1至7的某一数字,不同棋子上标的数字不相同。棋盘上还有一个空格(用0表示),与空格相邻(上下左右)的棋子可以移到空格中,该棋子原先位置成为空格。给出一个初始状态(保证可以转移到最终状态),找出一种从初始状态转变成给定最终状态(0 1 2 3 4 5 6 7)的移动棋子步数最少的移动步骤。 
         输入:多组输入,每组8个数,表示初始状态前四个数为第一行从左到右,后四个数为第二行从左到右。 
         输出:至少需要多少步可以从输入状态到达最终状态(0 1 2 3 4 5 6 7) 

思路:1.从反向思考,从"0 1 2 3 4 5 6 7",得到其它序列string的组合(这一过程用到BFS),并记录所需的步数,即为string到"0 1 2 3 4 5 6 7"所需的步数。

注:
1.调试在map<string, int>中是否已经找到了所有组合的序列和它所需的步数,可以使用注释掉的那段代; 2.remove函数和erase函数的功能: 点击打开链接(写的很好,建议看看)。
3.相邻两个元素移动时要注意不能在第4个和第5个数据之间移动(也就是第一行的最后一个元素和第二行的第一个元素)。

#include<iostream>
#include<map>
#include<string>
#include<queue>
#include<algorithm>
using namespace std;
typedef pair<string, int> P;
map<string, int> dp;
short op[4] = {-4, 4, -1, 1};

string a;
int bfs();
int solve();
int main()
{
    while(getline(cin, a))
       cout<<solve()<<endl;
    return 0;
}

int bfs()
{
    queue<P> q;
    P p, temp, now;//表示起始序列为"01234567",并且目前0所在的位置为0
    dp["01234567"] = 0;
    q.push(P("01234567", 0));//把起始点放入队列中
    while(!q.empty()){
        temp = q.front();
        q.pop();
        int cur = temp.second;
        for(int i = 0; i < 4; i++){
            int next = cur + op[i];
            string str = temp.first;//将队头元素的string赋值给str
            swap(str[cur], str[next]);//交换两个元素的位置
            map<string, int>::iterator it = dp.find(str);//在map中找str字符串
            if(next >= 0 && next < 8 && !(cur == 3 && next == 4) && !(cur == 4 && next == 3) && it == dp.end()){
                now.first = str; now.second = next;
                dp[now.first] = dp[temp.first] + 1;
                q.push(now);
            }
        }
    }

    /*map<string, int>::iterator it = dp.begin();
    while(it != dp.end()){
        cout<<(it->first)<<'\t'<<(it->second)<<endl;
        it++;
    }   */
    return -1;
}

int solve()
{
    a.erase(remove(a.begin(), a.end(), ' '), a.end());
    bfs();
    return dp[a];
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值