P1379 八数码难题 代码解析

八数码难题

题目链接:

  • 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;	
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值