Problem 洛谷P1379-八数码难题
Accept: 2.9k Submit: 8.3k
Time Limit: 1000 mSec Memory Limit : 128MB
Problem Description
在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。
Input
输入初始状态,一行九个数字,空格用0表示
Output
只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊无法到达目标状态数据)
Sample Input
283104765
Sample Output
4
题目链接:https://www.luogu.org/problemnew/show/P1379
题解:经典的八数码问题,其实还是比较简单的,两个需要注意的地方,一是判重,二是双向BFS。
判重,由于是0~8的排列,因此用康托展开来判重是很好的选择,不用处理冲突。
双向BFS无论是在空间上还是在时间上都比BFS优化了不少,操作也很容易,基本就是把bool型的vis数组变成int型,不同状态扩展来的做不同标记即可。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <queue> 6 #include <algorithm> 7 using namespace std; 8 9 const int maxn = 400000; 10 int Fac[10] = {1,2,6,24,120,720,5040,40320,362880}; 11 int vis[maxn],dis[maxn]; 12 13 int Cantor(int num[10]){ 14 int ans = 0; 15 for(int i = 0;i < 9;i++){ 16 int cnt = 0; 17 for(int j = i+1;j < 9;j++){ 18 if(num[j] < num[i]) cnt++; 19 } 20 ans += Fac[7-i]*cnt; 21 } 22 ans++; 23 return ans; 24 } 25 26 struct Point{ 27 int pai[10]; 28 int sit,flag,pos; 29 Point() {} 30 Point(int sit = 0,int flag = 0,int pos = 0) : 31 sit(sit),flag(flag),pos(pos) {} 32 }; 33 34 int Tar[10] = {1,2,3,8,0,4,7,6,5}; 35 int Ori[10]; 36 int dir[4][2] = {{1,0},{0,1},{-1,0},{0,-1}}; 37 int ori,tar,loc; 38 queue<Point> que; 39 40 bool Judge(int x,int y){ 41 if(0<=x && 0<=y && x<3 && y<3) return true; 42 return false; 43 } 44 45 int DBFS(){ 46 Point first(ori,1,loc),second(tar,2,4); 47 memcpy(first.pai,Ori,sizeof(Ori)); 48 memcpy(second.pai,Tar,sizeof(Tar)); 49 que.push(first),que.push(second); 50 vis[ori] = 1; 51 vis[tar] = 2; 52 dis[ori] = dis[tar] = 0; 53 while(!que.empty()){ 54 Point first = que.front(); 55 que.pop(); 56 int x = first.pos/3,y = first.pos%3; 57 for(int i = 0;i < 4;i++){ 58 int xx = x+dir[i][0],yy = y+dir[i][1]; 59 if(Judge(xx,yy)){ 60 Point temp = first; 61 swap(temp.pai[first.pos],temp.pai[xx*3+yy]); 62 int con = Cantor(temp.pai); 63 if(!vis[con]){ 64 vis[con] = first.flag; 65 temp.pos = xx*3+yy; 66 temp.sit = con; 67 dis[con] = dis[first.sit]+1; 68 que.push(temp); 69 } 70 else{ 71 if(vis[con] != first.flag){ 72 return 1+dis[con]+dis[first.sit]; 73 } 74 } 75 } 76 } 77 } 78 return -1; 79 } 80 81 int main() 82 { 83 //freopen("input.txt","r",stdin); 84 for(int i = 0;i < 9;i++){ 85 scanf("%1d",&Ori[i]); 86 if(Ori[i] == 0) loc = i; 87 } 88 ori = Cantor(Ori); 89 tar = Cantor(Tar); 90 if(ori == tar){ 91 printf("%d\n",0); 92 return 0; 93 } 94 memset(vis,0,sizeof(vis)); 95 printf("%d\n",DBFS()); 96 return 0; 97 }