题目描述
给定一个 n×m 的二维整数数组,用来表示一个迷宫,数组中只包含 0 或 1,其中 0 表示可以走的路,1 表示不可通过的墙壁。
最初,有一个人位于左上角 (1,1) 处,已知该人每次可以向上、下、左、右任意一个方向移动一个位置。
请问,该人从左上角移动至右下角 (n,m) 处,至少需要移动多少次。
数据保证 (1,1) 处和 (n,m) 处的数字为 0,且一定至少存在一条通路。
输入格式
第一行包含两个整数 n 和 m。
接下来 n 行,每行包含 m 个整数(0 或 1),表示完整的二维数组迷宫。
输出格式
输出一个整数,表示从左上角移动至右下角的最少移动次数。
数据范围
1≤n,m≤100
输入样例:
5 5
0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0
输出样例:
8
AC代码:
#include
#include
#include
#include
#include
#define x first
#define y second
using namespace std;
const int N = 110;
int n, m, cnt;
int g[N][N];
int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0, 0};
int bfs(){
queue<pair<int, int>> q;
q.push({0, 0});
while(!q.empty()){
int size = q.size();
cnt ++ ;
for(int j = 0; j < size; j ++ ){
auto tem = q.front();
q.pop();
if(tem.x == n - 1 && tem.y == m - 1) return cnt;
for(int i = 0; i < 4; i ++ ){
int nx = tem.x + dx[i], ny = tem.y + dy[i];
if(nx < 0 || ny < 0 || nx >= n || ny >= m) continue;
if(g[nx][ny] == 1) continue;
q.push({nx, ny});
g[nx][ny] = 1;
}
}
}
}
int main(){
cin >> n >> m;
for(int i = 0; i < n; i ++ )
for(int j = 0; j < m; j ++ )
scanf("%d", &g[i][j]);
int ans = bfs();
cout << ans - 1 << endl;
return 0;
}
例题1:
题目背景描述:
农夫约翰有一片 N∗M 的矩形土地。
最近,由于降雨的原因,部分土地被水淹没了。
现在用一个字符矩阵来表示他的土地。
每个单元格内,如果包含雨水,则用”W”表示,如果不含雨水,则用”.”表示。
现在,约翰想知道他的土地中形成了多少片池塘。
每组相连的积水单元格集合可以看作是一片池塘。
每个单元格视为与其上、下、左、右、左上、右上、左下、右下八个邻近单元格相连。
请你输出共有多少片池塘,即矩阵中共有多少片相连的”W”块。
输入格式
第一行包含两个整数 N 和 M。
接下来 N 行,每行包含 M 个字符,字符为”W”或”.”,用以表示矩形土地的积水状况,字符之间没有空格。
输出格式
输出一个整数,表示池塘数目。
数据范围
1≤N,M≤1000
输入样例:
10 12
W…WW.
.WWW…WWW
…WW…WW.
…WW.
…W…
…W…W…
.W.W…WW.
W.W.W…W.
.W.W…W.
…W…W.
输出样例:
3
dfs解法:
直接搜索每一个“ W ”周围是否还有“ W ”.如果有,就将其变为“ . ”.再统计答案即可.
#include
#include
#include
using namespace std;
const int N = 1010;
int n, m, cnt;
char s[N][N];
int dx[8] = {1, -1, 0, 0, 1, -1, 1, -1};
int dy[8] = {0, 0, 1, -1, 1, -1, -1, 1};
void dfs(int x, int y){
s[x][y] = '.';
for(int i = 0; i < 8; i ++ )
{
int a = x + dx[i], b = y + dy[i];
if(s[a][b] == 'W')
dfs(a, b);
}
}
int main(){
cin >> n >> m;
for(int i = 1; i <= n; i ++ )
for(int j = 1; j <= m; j ++ )
cin >> s[i][j];
for(int i = 1; i <= n; i ++ )
for(int j = 1; j <= m; j ++ )
if(s[i][j] == 'W'){
dfs(i, j);
cnt ++ ;
}
cout << cnt << endl;
return 0;
}
bfs解法:
#include
#define x first
#define y second
using namespace std;
const int N = 1010;
int n, m;
char s[N][N];
bool st[N][N];
int dx[8] = {0, 0, 1, -1, 1, -1, -1, 1};
int dy[8] = {1, -1, 0, 0, 1, -1, 1, -1};
void bfs(int a, int b){
queue<pair<int, int>> q;
q.push({a, b});
st[a][b] = true;
while(!q.empty()){
auto t = q.front();
q.pop();
a = t.x, b = t.y;
for(int i = 0; i < 8; i ++ )
{
int na = a + dx[i], nb = b + dy[i];
if(na < 0 || na >= n || nb < 0 || nb >= m) continue;
if(s[na][nb] == '.' || st[na][nb]) continue;
st[na][nb] = true;
q.push({na, nb});
}
}
}
int main(){
scanf("%d%d", &n, &m);
for(int i = 0; i < n; i ++ )
for(int j = 0; j < m; j ++ )
cin >> s[i][j];
int cnt = 0;
for(int i = 0; i < n; i ++ )
for(int j = 0; j < m; j ++ )
if(s[i][j] == 'W' && st[i][j] == false)
{
bfs(i, j);
cnt ++ ;
}
cout << cnt << endl;
return 0;
}
例题:
题目背景描述:
给定一个 n×n 的二维数组,如下所示:
int maze[5][5] = {
0, 1, 0, 0, 0,
0, 1, 0, 1, 0,
0, 0, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 1, 0,
};
它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的最短路线。
数据保证至少存在一条从左上角走到右下角的路径。
输入格式
第一行包含整数 n。
接下来 n 行,每行包含 n 个整数 0 或 1,表示迷宫。
输出格式
输出从左上角到右下角的最短路线,如果答案不唯一,输出任意一条路径均可。
按顺序,每行输出一个路径中经过的单元格的坐标,左上角坐标为 (0,0),右下角坐标为 (n−1,n−1)。
数据范围
0≤n≤1000
输入样例:
5
0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0
输出样例:
0 0
1 0
2 0
2 1
2 2
2 3
2 4
3 4
4 4
AC代码:
#include
#include
#include
#include
#define x first
#define y second
using namespace std;
typedef pair<int,int> PII;
const int N = 1010;
int n;
int s[N][N];
PII path[N][N];
void bfs(int sx, int sy){
int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0, 0};
queue<PII> q;
q.push({sx, sy});
memset(path, -1, sizeof path);
path[n - 1][n - 1] = {0, 0};
while(q.size()){
auto t = q.front();
q.pop();
for(int i = 0; i < 4; i ++ )
{
int nx = t.x + dx[i], ny = t.y + dy[i];
if(nx < 0 || ny < 0 || nx >= n || ny >= n) continue;
if(path[nx][ny].x != -1) continue;
if(s[nx][ny] == 1) continue;
q.push({nx, ny});
path[nx][ny] = t;
}
}
}
int main(){
cin >> n;
for(int i = 0; i < n; i ++ )
for(int j = 0; j < n; j ++ )
cin >> s[i][j];
bfs(n - 1, n - 1);
PII end = {0, 0};
while(true){
cout << end.x << " " << end.y << endl;
if(end.x == n - 1 && end.y == n - 1) break;
end = path[end.x][end.y];
}
return 0;
}
例题:
题目背景描述:
给定一个 N 行 M 列的 01 矩阵 A,A[i][j] 与 A[k][l] 之间的曼哈顿距离定义为:
dist ( A[ i ] [ j ] ,A [ k ] [ l ]) = | i − k | + | j − l |
输出一个 N 行 M 列的整数矩阵 B,其中:
B [ i ] [ j ] = m i n 1 ≤ x ≤ N , 1 ≤ y ≤ M , min_{1≤x≤N,1≤y≤M,} min1≤x≤N,1≤y≤M,A[x][y]=1dist(A[i][j],A[x][y])
输入格式
第一行两个整数 N,M。
接下来一个 N 行 M 列的 01 矩阵,数字之间没有空格。
输出格式
一个 N 行 M 列的矩阵 B,相邻两个整数之间用一个空格隔开。
数据范围
1≤N,M≤1000
输入样例:
3 4
0001
0011
0110
输出样例:
3 2 1 0
2 1 0 0
1 0 0 1
AC代码:
#include
#include
#include
#include
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
const int N = 1010;
int n, m;
char s[N][N];
int res[N][N];
void bfs(){
int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0, 0};
memset(res, -1, sizeof res);
queue<PII> q;
for(int i = 1; i <= n; i ++ )
for(int j = 1; j <= m; j ++ )
if(s[i][j] == '1')
{
q.push({i, j});
res[i][j] = 0;
}
int cnt = 0;
while(q.size()){
int size = q.size();
cnt ++ ;
for(int i = 0; i < size; i ++ ){
auto t = q.front();
q.pop();
for(int j = 0; j < 4; j ++ ){
int nx = t.x + dx[j], ny = t.y + dy[j];
if(nx < 0 || ny < 0|| nx > n || ny > m) continue;
if(res[nx][ny] != -1) continue;
res[nx][ny] = cnt;
q.push({nx, ny});
}
}
}
}
int main(){
cin >> n >> m;
for(int i = 1; i <= n; i ++ ) cin >> s[i] + 1;
bfs();
for(int i = 1; i <= n; i ++ )
{
for(int j = 1; j <= m; j ++ )
cout << res[i][j] << " ";
cout << endl;
}
return 0;
}