1. 程式人生 > >【Aizu - 0121】Seven Puzzle (反向bfs)

【Aizu - 0121】Seven Puzzle (反向bfs)

-->Seven Puzzle

原文是日語 這裡就直接寫中文了

 Descriptions:

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 6,圖(c)為2 7 3 4 0 5 1 6。

input

以上格式提供多個謎題。請處理到輸入的最後。給定的謎題的數量在1,000以下。

output

請將每個拼圖輸出到最後一行的最小麻煩。

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

題目連結:
https://vjudge.net/problem/Aizu-0121

從目標卡牌序列"01234567"開始著手入佇列,然後走出不同的卡牌序列,再將走出這些卡牌序列的步數儲存,最後比對題目要求的卡牌序列,找出答案即可,程式碼有詳解

AC程式碼:

#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
#include <sstream>
#define mod 1000000007
#define eps 1e-6
#define ll long long
#define INF 0x3f3f3f3f
#define MEM(x,y) memset(x,y,sizeof(x))
#define Maxn 310
using namespace std;
map<string,int>mp;//卡牌序列對應的步數
queue<string>q;//卡牌序列
string now,net;
string s;
//移動方向,右,左,上,下(給定一維陣列,要向上(下),就是往前(後)推四張牌)
int dt[]= {1,-1,4,-4};
void bfs()
{
    q.push("01234567");
    while(!q.empty())
    {
        now=q.front();
        q.pop();
        int pos=now.find('0');//找到0的位置
        for(int i=0; i<4; i++)
        {
            int tpos=pos+dt[i];
            //3、7位置不能往右移   0、4位置不能往左移
            if(tpos>=0&&tpos<8&&(!((pos==3||pos==7)&&i==0)&&!((pos==0||pos==4)&&i==1)))
            {
                net=now;
                swap(net[pos],net[tpos]);//交換pos和tpos位置的數字,形成新的卡牌序列
                if(mp[net]==0)//卡牌序列沒出現過
                {
                    mp[net]=mp[now]+1;//步數+1
                    q.push(net);
                }
            }
        }
    }
    return;
}
int main()
{
    bfs();//初始化,找出所有可能的卡牌序列
    mp["01234567"] = 0;
    while(1)
    {
        s="";//存放題目要求的卡牌序列
        int a = 8,b;
        while(a--)
        {
            if(!(cin >> b))
                return 0;//這一行的處理是加了個結尾,不加的話死迴圈
            s += b+'/0';
        }
        cout <<mp[s] << endl;
    }
    return 0;
}

&n