【洛谷1379】八数码

问题描述

在3*3的九宫格棋盘中,摆有8个将牌,每个将牌上刻有1-8中的某一个数码。棋盘中留有一个空格,允许其四周的某一个将牌向空格移动,这样通过移动将牌就可以不断改变布局。给定一种初始布局,求变为目标布局所需的最少步数。

目标布局为:

1 2 3

8 0 4

7 6 5

其中0表示空格。

输入格式

三行共9个数,表示初始布局

输出格式

一个整数表示变为目标布局的最少步数。若无解输出“no solution”

样例输入

0 1 3

8 2 4

7 6 5

样例输出

2

题解

从初始布局开始广搜。

关键是状态的保存和判重比较麻烦。

直接用3*3的形式保存肯定会爆的,考虑到一个状态只有九个数,可以把这九个数压缩成一个九位数,保存的问题就解决了。一个状态有九个格子,每个格子填一个数有9种填法(0~8),九个格子一共9!种填法,不超过4e5,队列开4e5就够了。

接下来,怎么判重呢?如果每得出一个状态就和前面所有状态比较一遍,显然会TLE;如果用一个布尔数组来记录每种状态是否出现过,也要开876543210的数组,直接MLE了。由于最多只有9!种状态,其实只要标记这9!种状态有没有出现过就可以了。怎么把876543210压缩成9!呢?哈希!找个大质数,判断每个状态的模有没有出现过就行了。

 1 #include <cstdio>
 2 const int dx[10][5]={ {0,0,0,0,0},{2,2,4,0,0},{3,1,3,5,0},
 3                       {2,2,6,0,0},{3,1,5,7,0},{4,2,4,6,8},
 4                       {3,3,5,9,0},{2,4,8,0,0},{3,5,7,9,0},
 5                       {2,6,8,0,0}
 6                     };
 7 const int ds[10]={1,10,100,1000,10000,1e5,1e6,1e7,1e8,1e9};
 8 const int inf=4e5+1,m=123804765;
 9 int f[400005][10],q[400005][2],n;
10 bool check(int x)
11 {
12     int s=x%inf;
13     if (!f[s][0])
14     {
15         f[s][++f[s][0]]=x;
16         return 1;
17     }
18     for (int i=1;i<=f[s][0];i++)
19       if (f[s][i]==x)
20         return 0;
21     f[s][++f[s][0]]=x;
22     return 1;
23 }
24 int getzero(int x)
25 {
26     int i,pre=x%10,s;
27     if (!pre) return 1;
28     for (i=2;i<=9;i++)
29     {
30         s=x%ds[i];
31         if (s==pre) return i;
32         pre=s;
33     }
34     return 9;
35 }
36 int bfs()
37 {
38     if (n==m) return 0;
39     int h=0,t=1,i,j,k,x,y,s,u;
40     q[1][1]=n;
41     check(n);
42     while (h!=t)
43     {
44         h++;
45         u=q[h][1];
46         x=getzero(u); 
47         for (i=1;i<=dx[x][0];i++)
48         {
49             j=dx[x][i];
50             y=(u/ds[j-1])%10;  
51             s=u-y*ds[j-1]+y*ds[x-1];  
52             if (check(s))
53             {
54                 if (s==m) return q[h][0]+1;
55                 q[++t][1]=s;
56                 q[t][0]=q[h][0]+1;
57                 
58             }
59         }
60         
61     }
62     return -1;
63 }
64 int main()
65 {
66     int i,j,x;
67     /*for (i=1;i<=9;i++)
68       scanf("%d",&x),
69       n=n*10+x;*/
70     scanf("%d",&n);  
71     int ans=bfs();
72     if (ans!=-1) printf("%d",ans);
73     else printf("no solution");
74     return 0;  
75 }

猜你喜欢

转载自www.cnblogs.com/rabbit1103/p/9197908.html