洛谷P1379-八数码难题

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 }

猜你喜欢

转载自www.cnblogs.com/npugen/p/9496008.html