洛谷 P1379 八数码难题
JDOJ 1461: VIJOS-P1360 八数码问题
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]);
}
}
}