试题 历届试题 九宫重排

 

资源限制
时间限制:1.0s   内存限制:256.0MB
 
问题描述
  如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着。与空格子相邻的格子中的卡片可以移动到空格中。经过若干次移动,可以形成第二个图所示的局面。

  我们把第一个图的局面记为:12345678.
  把第二个图的局面记为:123.46758
  显然是按从上到下,从左到右的顺序记录数字,空格记为句点。
  本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。
 
输入格式
  输入第一行包含九宫的初态,第二行包含九宫的终态。
 
输出格式
  输出最少的步数,如果不存在方案,则输出-1。
 
样例输入
12345678.
123.46758
 
样例输出
3
 
样例输入
13524678.
46758123.
 
样例输出
22
 
 
这题与状态和步数相关,首先就是想到搜索,要得到从初态到终态所需最少步数→广搜,一旦出现终态那就是最少步数.
第一遍写的时候没有记录出现过的局面进行剪枝,于是超时了,后来用map记录出现过的局面,每个局面都用一个字符串表示,重复出现的局面就不再入队了,这样修改之后再提交就能过了.
不过这种方法并不是很好,耗时长,占内存大(375ms | 21.98MB),搜了一些别人的代码提交了一下,都比这种方法更优(15ms | 13.77MB,125ms | 10.83MB),不过对我来说这种方法比较好理解,也容易想到,总之思路没歪就好.
 
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <string>
 6 #include <cmath>
 7 #include <map>
 8 #include <queue>
 9 #include <algorithm>
10 #define INF 0x3f3f3f3f
11 #define zero 1e-7
12 
13 using namespace std;
14 typedef long long ll;
15 const ll mod=1e9+7;
16 const ll max_n=5e5+7;
17 //9*8*7*6*5*4*3*2*1=362880
18 struct node {
19     string s;//当前局面
20     int p;//该局面空格所在位置
21     int step;//到达当前局面经过了多少步
22 };
23 queue<node> q;
24 map<string, int> mp;//记录出现过的局面
25 
26 string s1, s2;//初态,终态
27 
28 void add(node t, int p) {//当前局面,新局面中空格所在位置
29     string ss=t.s;
30     ss[t.p]=ss[p];
31     ss[p]='.';
32     if(mp.find(ss)==mp.end()) {//若局面ss未曾出现过
33         mp[ss]=1;//记录该局面
34         node temp={ss, p, t.step+1};
35         q.push(temp);//将该局面相关信息入队
36     }
37 }
38 //广搜
39 int bfs() {
40     while(!q.empty()) {
41         node t=q.front();
42         q.pop();
43         if(t.s==s2) {//一旦该局面与目标局面一致,其步数即最少所需步数
44             return t.step;
45         }
46         int pp;
47         string ss;
48         if(t.p/3>0) //空格不在第一行,可与它上方那格数字交换
49             add(t, t.p-3);
50         if(t.p/3<2) //空格不在第三行,可与它下方那格数字交换
51             add(t, t.p+3);
52         if(t.p%3>0) //空格不在第一列,可与它左边那格数字交换
53             add(t, t.p-1);
54         if(t.p%3<2) //空格不在第三列,可与它右边那格数字交换
55             add(t, t.p+1);
56     }
57     return -1;//若无法达到目标局面,则返回-1
58 }
59 
60 int main() {
61     int p;
62     mp.clear();
63     while(!q.empty()) q.pop();//队列清空
64     cin>>s1>>s2;
65     for(int i=0; i<9; i++) {
66         if(s1[i]=='.') {
67             p=i;
68             break;
69         }
70     }
71     node temp={s1, p, 0};//当前局面,空格的位置,步数
72     q.push(temp);
73     mp[temp.s]=1;
74     int mint=bfs();
75     cout<<mint<<endl;
76     return 0;
77 }
 
posted @ 2020-08-30 19:40  自在逍遥处  阅读(212)  评论(0编辑  收藏  举报