蓝桥杯 试题 历届试题 九宫重排 BFS+剪枝

问题描述
  如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着。与空格子相邻的格子中的卡片可以移动到空格中。经过若干次移动,可以形成第二个图所示的局面。

  我们把第一个图的局面记为:12345678.
  把第二个图的局面记为:123.46758
  显然是按从上到下,从左到右的顺序记录数字,空格记为句点。
  本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。
输入格式
  输入第一行包含九宫的初态,第二行包含九宫的终态。
输出格式
  输出最少的步数,如果不存在方案,则输出-1。
样例输入
12345678.
123.46758
样例输出
3
样例输入
13524678.
46758123.
样例输出
22
解题思路:
  • 由于BFS每次向最近状态一步步改变,所以一般情况下求最小操作步数首先考虑。
  • 与青蛙跳杯子思路相同 https://www.cnblogs.com/w-like-code/p/12983954.html  用set进行剪纸,防止两个相邻状态反复出现;
注意剪枝时机,防止一个状态多次计算(在将该状态加入队列时就要加入集合)
  • 这里与🐸问题唯一不同的是输入是一行字符而实际移动时是九宫格,用一个3*3数组即可。
解决代码:
 1 #include<iostream>
 2 #include<string>
 3 #include<set>
 4 #include<queue>
 5 #include<algorithm>
 6 using namespace std;
 7 
 8 struct state
 9 {
10     string str;
11     int step;
12     state(string str_, int step_)
13     { /*构造函数*/
14         str = str_; step = step_;
15     }
16 };
17 
18 //输入
19 string begin,end; /*初始局面和目标局面*/ 
20 
21 int dx[] = {0,0,1,-1}, dy[] = {1,-1,0,0}; //x,y方向向量
22 
23 int bfs();
24 
25 int main()
26 {
27     cin>>begin>>end;
28     
29     cout<<bfs()<<endl;
30     
31     return 0;
32 }
33 
34 int bfs()
35 {
36     queue<state> que;
37     set<string> s; /*用于剪枝*/ 
38     
39     que.push( state(begin,0) );
40     s.insert(begin);
41     
42     while( que.size() )
43     {
44         state current = que.front(); que.pop();
45         string str = current.str; int step = current.step;
46         
47         if( str==end ){
48             return step;
49         }
50         
51         char mat[3][3];
52         int x,y; /*保存空格坐标*/ 
53         
54         for( int i=0; i<3; i++ )
55         { /*将字符串转为九宫格*/ 
56             for( int j=0; j<3; j++ )
57             {
58                 mat[i][j] = str[i*3+j];
59                 if( mat[i][j]=='.' )
60                 {
61                     x = i; y = j;    
62                 } 
63             }    
64         } 
65         
66         /*遍历四个可能的方向 */ 
67         for( int i=0; i<4; i++ )
68         {
69             int nx = x + dx[i], ny = y + dy[i];
70             if( 0<=nx&&nx<3 && 0<=ny&&ny<3 ) /*满足条件*/ 
71             {
72                 swap(str[x*3+y],str[nx*3+ny]);
73                 if( !s.count(str) )/*是否剪枝*/ 
74                 {
75                     s.insert(str);
76                     que.push( state(str,step+1));
77                 }
78                 swap(str[x*3+y],str[nx*3+ny]); /*回溯*/ 
79             }
80         }
81     }
82     
83     return -1;
84 } 

 

 
posted @ 2020-10-07 21:04  代码改变头发  阅读(219)  评论(0编辑  收藏  举报