道馆之战!!!这一次,道馆由电系变为了冰系,和龙系的道馆不一样,冰系的道馆有冰系的规定。如图所示,一共有三层,上面一层总是比下面一层要复杂一些。在冰系道馆中,有如下的两个规则:(1)我们不会在冰面上划来划去了,但是冰是会破裂的,也就是说,你每在上面走过之后,就不能继续在上面行走了(2)你只有走完了这一层的所有冰块,上面一层的门才会向你开启,直到最后的道馆馆主。
网上口袋妖怪大神的策略:
首先,我们还是来看一看那些大神们是来解决这一问题的:
如图,这是中间一层的行走方式,貌似也只有这一种情况了。起点位于圆圈的地方。由于右边有一个石头遮掩着,而左边没有,所以我们考虑从左边开始行走,这样,我们有了第一条原则,就是,看一行或者一列,如果沿着这一行或者这一列前进的方向上没有岩石的阻挡而可以直接到达底部的话(如果那一点已经走过,则可以标记为石头),那么就往这个方向走。这当然是一个贪心的想法,其正确性没有得到验证,而且,有时候是不行的。比如,如果主角在中央,而其左边和右边都没有石头的话,则无法选择一个稳定的一条路了。
我们的AI策略:
我们的AI策略如下,考虑到我在Round 13中,也就是吴昊教你走迷宫的另一种变式中的一个技法,这里只需要略作更改,即可。我们不妨对比一下两者的区别,可以得到如下的结论:
(A)这里没有定式炸弹,也没有定时炸弹的重置器,问题会简单许多。
(B)与之不同的是,当经过了一个冰块之后,这里的冰块会发生破裂,也就是以后就不能经过了,于是,这里必须标记一个数字,以区别冰块破裂之前与破裂之后的区别,所以,我们将破裂之前的冰块以数字1标识而破裂之后的冰块以数字5来标识。
(C)终点的条件不同,在Round 13中,终点的条件为在定时炸弹还没有爆炸之前逃离出口,而在我们这里,终点的条件为到达终点时,这一区域内的所有的冰块全部破裂。
(D)这里有三层,也就是三种不同的地图,我们也可以理解成,这三个样例只有都满足条件,我们才能见到最后的BOSS。
有了以下的分析,我们这里做一个约定,用一个int类型的二维数组来表征地图,数字2代表我们的主角小智的起点,3代表终点,4代表障碍物,1代表还没有破裂的冰块,而当冰块破裂之后,我们将其重新设置为数字5。这样,对于每一个输入的地图,我们都可以判断出是否可以最终达到终点(如果要拿到具体的路径的话,我们可以设置一个标记,当然,这很容易实现了,这里略去)。
Solve:
1 #include<iostream>
2
3
//
这里还是运用队列容器来实现
4
5 #include<queue>
6
7
using
namespace std;
8
9
10
11
//
首先是地图map[][],n,m为地图的实际的长和宽,(si,sj)为开始的点,mins
12
13
int map[
9][
9],n,m,si,sj;
14
15
bool success;
16
17
18
19
//
方向数组
20
21
int dir[
4][
2]={{
1,
0},{-
1,
0},{
0,
1},{
0,-
1}};
22
23
24
25
//
障碍物的总数
26
27
int w;
28
29
30
31
struct node
32
33 {
34
35
//
cnt走格子数
36
37
int x,y,cnt;
38
39 };
40
41
42
43 node f;
44
45
46
47
void bfs()
48
49 {
50
51 f.x=si;
52
53 f.y=sj;
54
55
//
已经走过的格子数为0
56
57 f.cnt=
0;
58
59 queue<node> q;
60
61 q.push(f);
62
63
//
如果队列整个空了,则退出
64
65
while(!q.empty())
66
67 {
68
69 node t=q.front();
70
71 map[t.x][t.y]=
5;
72
73 q.pop();
74
75
if(map[t.x][t.y]==
3)
76
77 {
78
79
//
找到终点了,如果还剩余时间的话,将已经花费的时间输出
80
81
if(t.cnt==(n*m-w))
82
83 {
84
85 success=
true;
86
87
return;
88
89 }
90
91
else
continue;
92
93 }
94
95
for(
int k=
0;k<
4;k++)
96
97 {
98
99
//
定义一个NEXT结点,这个在前面的吴昊系列已经阐述过了
100
101 node b;
102
103 b.x=t.x+dir[k][
0];
104
105 b.y=t.y+dir[k][
1];
106
107
//
将已经花费的时间++,而剩余的时间--
108
109 b.cnt=t.cnt+
1;
110
111
/*
112
113
入队的条件,这里有如下一些条件:
114
115
(1)首先,必须在迷宫的范围之内
116
117
(2)这个位置不是一堵墙
118
119
(3)这个位置还没有被走过
120
121
*/
122
123
if(b.x<=n&&b.x>
0&&b.y<=m&&b.y>
0&&map[b.x][b.y]!=
5)
124
125 {
126
127 q.push(b);
128
129 }
130
131 }
132
133 }
134
135 }
136
137
138
139
int main()
140
141 {
142
143
int t;
144
145
//
样例的总数
146
147 cin>>t;
148
149
while(t--)
150
151 {
152
153 w=
0;
154
155
//
地图的长与宽
156
157 cin>>n>>m;
158
159
for(
int i=
1;i<=n;i++)
160
161 {
162
163
for(
int j=
1;j<=m;j++)
164
165 {
166
167
//
将地图中的元素进行分类
168
169 cin>>map[i][j];
170
171
if(map[i][j]==
2)
172
173 {
174
175 si=i;
176
177 sj=j;
178
179 }
180
181
if(map[i][j]==
4)
182
183 {
184
185 w++;
186
187 }
188
189 }
190
191 }
192
193 bfs();
194
195
if(success==
true)
196
197 cout<<
"
success
"<<endl;
198
199
else cout<<
"
false
"<<endl;
200
201 }
202
203
return
0;
204
205 }
最后,我还是废话一句吧!口袋妖怪中,这种冰面破碎的场景并不一定局限在道馆战役中,有时候,它甚至和龙系道馆的某些场景结合起来,比如下面一个场景,我想大家应该都还印象深刻吧!
如图所示,当你踩着一辆自行车的时候,首先,你不得不滑动,只能借助障碍物进行移动,另外,在踩过的地面上,如果你再踩一脚的话,则会破碎,你不得不陷入进去。所以,我说这一场景其实是冰系道馆场景与冰系道馆场景的完美结合,也是任天堂的口袋妖怪系列游戏的魅力!