说明:这原本是我很久之前出的一道题目。最近整理的时候发现这道题竟然还没写题解,就写了一下,顺便改&修了下题面。
题目描述
Farmer John的奶牛Besty进入了一个n*m的迷宫。
本题的特殊之处在于,Besty只能滑着走。具体来说就是,选定一个方向后,Besty会一直向该方向滑,直到撞到墙。
会给出Besty的起始位置。只需要滑出去即可。
求最小的撞墙次数。
输入格式
第一行两个整数n,m表示迷宫大小。
下面n行,每行m个整数,0表示空地,1表示墙。
最后一行两个整数sx,sy表示Besty初始位置。
输出格式
走出迷宫的最小撞墙次数。无解请输出-1。
样例
#1
输入
5 6
1 1 1 1 1 0
1 0 1 0 0 0
1 0 0 1 0 1
1 0 0 0 0 1
1 1 0 0 1 1
2 2
输出
3
#2
输入
5 3
1 1 1
1 0 1
0 0 1
1 0 1
1 1 1
2 2
输出
-1
数据范围
共16个测试点。其中前13个保证\(1\leq n,m\leq 30\)。最后3个保证\(1\leq n,m\leq 100\)
思路
别看题面整了这么个花样,但他毕竟还是个迷宫问题。再看数据范围,直接搜索就完事。
题解
正常的迷宫问题是每次把相邻的格子作为新的状态去搜索。
对于这道题目,我们也只需要从这个地方下手,把原本的搜索相邻格子变成搜索直到撞墙为止的格子即可。
代码实现上,我们可以跑一个while循环并维护当前位置,如果下一个格子是墙那么退出循环并把当前位置作为新的状态;否则往前走一步(把当前位置设为下一个格子)
代码
这里仅给出BFS的实现。DFS实现同理,核心代码是一样的。
#include <bits/stdc++.h>
using namespace std;
int n, m, sx, sy;
bool mat[501][501];
const int dx[4] = {0, 1, 0, -1}, dy[4] = {1, 0, -1, 0};
struct pos
{
int x, y, step;
pos(int x, int y, int step) : x(x), y(y), step(step) {}
};
queue<pos> q;
bool vis[501][501];
inline bool pan(int x, int y)
{
return x >= 1 && x <= n && y >= 1 && y <= m && mat[x][y] == 0;
}
bool out(int x, int y)
{
return (x == 1 || x == n || y == 1 || y == m) && mat[x][y] == 0;
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
cin >> mat[i][j];
}
}
cin >> sx >> sy;
if(mat[sx][sy]){
cout<<-1;
return 0;
}
if(out(sx,sy)){
cout<<0;
return 0;
}
q.push(pos(sx, sy, 0));
vis[sx][sy] = 1;
while (!q.empty())
{
pos h = q.front();
q.pop();
// cout << h.x << ' ' << h.y << endl;
if (out(h.x, h.y))
{
cout << h.step - 1;
return 0;
}
for (int i = 0; i < 4; i++)
{
int xx = h.x, yy = h.y;
while (pan(xx + dx[i], yy + dy[i]))
{
xx += dx[i];
yy += dy[i];
}
if ((xx == h.x && yy == h.y) || vis[xx][yy])
continue;
vis[xx][yy] = 1;
q.push(pos(xx, yy, h.step + 1));
}
}
cout << -1;
}