八数码难题
题目链接:
- link,点击这里喵。
题目描述
在 3 × 3 3\times 3 3×3 的棋盘上,摆有八个棋子,每个棋子上标有 1 1 1 至 8 8 8 的某一数字。棋盘中留有一个空格,空格用 0 0 0 来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为 123804765 123804765 123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。
输入格式
输入初始状态,一行九个数字,空格用 0 0 0 表示。
输出格式
只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数。保证测试数据中无特殊无法到达目标状态数据。
样例 #1
样例输入 #1
283104765
样例输出 #1
4
提示
样例解释
图中标有 0 0 0 的是空格。绿色格子是空格所在位置,橙色格子是下一步可以移动到空格的位置。如图所示,用四步可以达到目标状态。
并且可以证明,不存在更优的策略。
做法:
- 由于数据较大,故采用双向 bfs,压状态进行卡常,双向广搜说白了就是广搜然后记录一下来自哪边,最后加上另一侧就好。
- 没什么好说的,代码很简单。注意同侧去重和另一侧答案的区别
代码:
#include <stdio.h>
#include <ctype.h>
#include <algorithm>
#include <queue>
#include <map>
#define lnt long long
#define inf 0x3f3f3f3f
using namespace std;
int xx;char ff,chh;inline int read(){
xx=ff=0;while(!isdigit(chh)){if(chh=='-'){ff=1;}chh=getchar();}
while(isdigit(chh)){xx=(xx<<1)+(xx<<3)+chh-'0';chh=getchar();}return ff? -xx: xx;
}
const int N=3;
int base[]={1,10,100,1000,10000,100000,1000000,10000000,100000000};
int fx[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
inline int ys(int x,int y){return base[x*3+y];}
int getx(int v){for(int i=0,now=1;i<3;++i){for(int e=0;e<3;++e,now*=10){if(v/now%10==0){return i;}}}}
int gety(int v){for(int i=0,now=1;i<3;++i){for(int e=0;e<3;++e,now*=10){if(v/now%10==0){return e;}}}}
bool is(int x,int y){return x!=3 && x!=-1 && y!=3 && y!=-1;}
int swp(int x,int y,int tox,int toy,int v);
struct node{int v,b,d;};
struct ans{int b,d;};
int main(){
queue<node> q;
map<int,ans> vis;
q.push({read(),0,0});
q.push({123804765,1,0});
while(!q.empty()){
node u=q.front();
//printf("%d\n",u.v);
q.pop();
if(vis.find(u.v)==vis.end()){vis[u.v]={u.b,u.d};}
else{
ans t=vis[u.v];
if(t.b^u.b){printf("%d",t.d+u.d);return 0;}
}
int x=getx(u.v),y=gety(u.v);
//printf("%d\n%d\n",x,y);
for(int i=0;i<4;++i){
if(is(x+fx[i][0],y+fx[i][1])){
//printf("swp:%d\n",swp(x,y,x+fx[i][0],y+fx[i][1],u.v));
q.push({swp(x,y,x+fx[i][0],y+fx[i][1],u.v),u.b,u.d+1});
}
}
}
return 0;
}
int swp(int x,int y,int tox,int toy,int v){
int temp=v;
v-=ys(x,y)*(temp/ys(x,y)%10);
v+=ys(x,y)*(temp/ys(tox,toy)%10);
v-=ys(tox,toy)*(temp/ys(tox,toy)%10);
v+=ys(tox,toy)*(temp/ys(x,y)%10);
return v;
}