1. 程式人生 > 實用技巧 >洛谷 P1379 八數碼難題

洛谷 P1379 八數碼難題

洛谷 P1379 八數碼難題

洛谷傳送門

JDOJ 1461: VIJOS-P1360 八數碼問題

JDOJ傳送門

Description

在3×3的棋盤上,擺有八個棋子,每個棋子上標有1至8的某一數字。棋盤中留有一個空格,空格用0來表示。空格周圍的棋子可以移到空格中。要求解的問題是:給出一種初始佈局(初始狀態)和目標佈局(為了使題目簡單,設目標狀態為123804765),找到一種最少步驟的移動方法,實現從初始佈局到目標佈局的轉變。

Input

輸入初試狀態,一行九個數字,空格用0表示

Output

只有一行,該行只有一個數字,表示從初始狀態到目標狀態需要的最少移動次數(測試資料中無特殊無法到達目標狀態資料)

Sample Input

283104765

Sample Output

4


最優解宣告:


題解:

雙向BFS+map去重。

這裡採用了把序列化成矩陣的模式,方便繼續往下搜。

程式碼:

#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<map>
#include<queue>
#define ll long long int
using namespace std;
int n,g=123804765;
int a[4][4],fx,fy,nx,ny;
int dx[4]={1,-1,0,0};
int dy[4]={0,0,1,-1};
queue<int> q;
map<int,int> v,ans;
int main()
{
    scanf("%d",&n);
	if(n==g)
    {
        printf("0");
        exit(0);
    }				
    q.push(n);
    q.push(g);
    ans[n]=0;
    ans[g]=1;		
    v[g]=2;
    v[n]=1;
    while(!q.empty())
    {
        ll now,cur=q.front();
        q.pop();
        now=cur;
        for(int i=3;i>=1;i--)
            for(int j=3;j>=1;j--)
            {
                a[i][j]=now%10,now/=10;
                if(a[i][j]==0) fx=i,fy=j;
            }
        for(int i=0;i<4;i++)
        {
            nx=fx+dx[i];
            ny=fy+dy[i];
            if(nx<1 || nx>3 || ny<1 || ny>3) 
				continue;
            swap(a[fx][fy],a[nx][ny]);
            now=0;
            for(int p=1;p<=3;p++)
                for(int j=1;j<=3;j++)
                    now=now*10+a[p][j];
            if(v[now]==v[cur]) 
            {
                swap(a[fx][fy],a[nx][ny]);
                continue;
            }
            if(v[now]+v[cur]==3)
            {
                printf("%d",ans[cur]+ans[now]);
                exit(0);
            }
            ans[now]=ans[cur]+1;
            v[now]=v[cur];
            q.push(now);
            swap(a[fx][fy],a[nx][ny]);
        }	
    }
}