洛谷 P1443 马的遍历
题目链接
思路:
要求到一个点,马最少走多少步。bfs 从起点往四周辐射,最先达到的点,就是最短距离(最少的步数)。所以这题就是典型的 bfs,通过队列来做。
对于一个结点 Pos(取队首),根据中国象棋马走斜日的规则,我们可以判断有八个方向,分别遍历八个方向能够到达的点。如果遍历到的这个点 New_pos 满足两个条件:
没有遍历过。是一个新鲜的点。vis 数组中值为初始值 0 。使数组不越界!
那么它就是一个新的结点,将它在 vis 数组中标记后入队。它的 level (从起点到这个点是第几层,即需要走几步)就是前面那个节点 Pos 的 level +1。
点 Pos 的八个方向都遍历完成之后,就将 Pos 出队,然后遍历新的队列头结点。因为 Pos 在最开始入队的时候就标记过 vis 数组,所以它肯定不会再入队。
当所有能够到达的点都在 vis 数组中标记完成,队列就是空的了。(BFS套路)
bfs 完成。
实现细节:
马行走的八个方向。画个图就能够理解。用 dx[] 数组和 dy[] 表示位置的变换。马在的初始位置,到达的步数应该是 0 。但是如果在将初始节点入队的时候,将 level 设置为 0,那么后面有可能还会遍历到这个点,造成错误。我的解决办法是将初始节点的 level 设置为 1 ,那么后面输出答案时,所有的 level 都要 -1。数组是否越界的判断很重要!而且容易忘……在输出时要判断,如果是初始数据,则输出 0 ;如果是不能到达的点 vis[i][j] == 0,则输出 -1;其他情况则输出 vis[i][j] - 1。最后也是最重要的,输出格式。题目要求是每个答案占五格。那么,如果答案是初始数据的 0 ,后面就要跟 4 个空格;如果答案是 -1 ,后面就要跟三个空格;同理,其他情况中对一位数答案,二位数答案,三位数答案,后面都要跟相应位置的空格。
代码:
#include<bits/stdc++.h>
using namespace std
;
int gra
[405][405];
int vis
[405][405];
struct point
{
int x
;
int y
;
int level
;
};
int dx
[]={-2,-1,1,2,2,1,-1,-2};
int dy
[]={1,2,2,1,-1,-2,-2,-1};
queue
<point
> q
;
int m
,n
;
void bfs(){
while(!q
.empty()){
point pos
=q
.front();
int x
=pos
.x
;
int y
= pos
.y
;
int level
= pos
.level
;
for(int i
=0;i
<8;i
++){
int x_new
= x
+ dx
[i
];
int y_new
= y
+ dy
[i
];
if(x_new
<=n
&& x_new
>0 && y_new
>0 && y_new
<=m
){
if(vis
[x_new
][y_new
]==0){
point new_pos
= {x_new
,y_new
,level
+1};
vis
[x_new
][y_new
] = level
+1;
q
.push(new_pos
);
}
}
}
q
.pop();
}
}
int main(){
int start_x
,start_y
;
cin
>>n
>>m
;
cin
>>start_x
>>start_y
;
point start
={start_x
,start_y
,1};
q
.push(start
);
vis
[start
.x
][start
.y
] = start
.level
;
bfs();
for(int i
=1;i
<=n
;i
++){
for(int j
=1;j
<=m
;j
++){
if(i
==start_x
&& j
==start_y
){
cout
<<0<<" ";
}
else if(vis
[i
][j
]==0){
cout
<<-1<<" ";
}
else{
int ans
= vis
[i
][j
]-1;
if(ans
<10) cout
<<ans
<<" ";
else if(ans
>=10 && ans
<= 99)
cout
<<ans
<<" ";
else if(ans
>=100) cout
<<ans
<<" ";
}
}
cout
<<endl
;
}
return 0;
}
最后:
突然才发现,洛谷虽然只能下载部分数据,但是对于每一个错误点其实都会给出提示。鼠标移到 WA 那的时候会有一段话出现,提示错误在哪一行哪一列,输出的错误答案是什么,正确答案 expected 是多少。
由于这些话是英文,以前都是当没看到或者看不懂,一头雾水,直接忽略。直到今天才发现其中玄妙。可见学好英语真的很重要啊!