P1379 八数码难题
漂亮小姐姐单击就送:https://www.luogu.org/problemnew/show/P1379
题目描述
在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。
输入输出格式
输入格式:
输入初始状态,一行九个数字,空格用0表示
输出格式:
只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊无法到达目标状态数据)
输入输出样例
输入样例#1: 复制
283104765
输出样例#1: 复制
bfs+八维数组
和别人比起来好慢的IDA*
4
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/*这道题一开始用的是map判重,TLE了俩点。然后改hash,全WA了,感觉我自己写hash选模数靠运气。 然后不写hash了,写进制位,AC了,因为知道了前八位数后,第九位就能确定,所以只求前八位数的和就可以。 */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<map> #include<string> #include<queue> using namespace std; int pos,x,y,ans; int sum; string s; char a[4][4]; struct state //记录搜索状态 { string s; //字符串表状态 int step; //到达这个状态需要几步 }now,temp; bool flag[88888888]; //八位数判重 queue<state> que; //搜索用的队列 int cx[4]={-1,0,1,0}; //改方向用的数组 int cy[4]={0,1,0,-1}; void mswap(char &a,char &b) //手写swap { char c; c=a;a=b;b=c; return; } string change() //将图转化成字符串,顺便求前八位数的和 { sum=0; string s; for(int i=1;i<=3;i++) { for(int j=1;j<=3;j++) { s+=a[i][j]; if(!(i==3&&j==3)) sum=sum*10+a[i][j]-'0'; //求前八位数 } } return s; } void bfs() { while(!que.empty()) { pos=0; now=que.front();que.pop(); for(int i=1;i<=3;i++) //转化成一个3*3的矩阵 { for(int j=1;j<=3;j++) { if(now.s[pos]=='0') x=i,y=j; a[i][j]=now.s[pos++]; } } for(int i=0;i<4;i++) //上下左右四个方向找 { if(x+cx[i]>0&&x+cx[i]<4&&y+cy[i]>0&&y+cy[i]<4) { mswap(a[x][y],a[x+cx[i]][y+cy[i]]); //换位 temp.s=change(); //将图转化成字符串,判重 if(temp.s=="123804765") //到达了目标状态,输出答案 { printf("%d",now.step+1); return; } if(!flag[sum]) //当前状态没出现过,添加状态 { flag[sum]=1; temp.step=now.step+1; que.push(temp); } mswap(a[x][y],a[x+cx[i]][y+cy[i]]); //再换回来 } } } } int main() { cin>>s; now.s=s;now.step=0; que.push(now); for(int i=0;i<8;i++) //初始状态判重 { sum=sum*10+s[i]-'0'; } flag[sum]=1; if(sum==12380476) puts("0"); else bfs(); return 0; }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; int n,m,x,y,ans,maxdep; int cx[5]={1,-1,0,0}; int cy[5]={0,0,-1,1}; int gx[9]={0,1,1,1,2,3,3,3,2}; int gy[9]={0,1,2,3,3,3,2,1,1}; int map[4][4]; int h() { int ans=0; for(int i=1;i<=3;i++) for(int j=1;j<=3;j++) if(map[i][j]) ans+=abs(i-gx[map[i][j]])+abs(j-gy[map[i][j]]); return ans; } void dfs(int X,int Y,int dep) { int H=h(); if(!H) { printf("%d",dep); exit(0); } if(dep==maxdep||H+dep>maxdep) return; for(int i=0;i<4;i++) { int x=X+cx[i]; int y=Y+cy[i]; if(x&&y&&x<4&&y<4) { swap(map[X][Y],map[x][y]); dfs(x,y,dep+1); swap(map[X][Y],map[x][y]); } } } char c; int main() { for(int i=1;i<=3;i++) for(int j=1;j<=3;j++) { cin>>c; map[i][j]=c^'0'; if(!map[i][j]) x=i,y=j; } if(!h()) { puts("0"); return 0; } for(maxdep=1;;++maxdep) { dfs(x,y,0); } }