题面:

解题:
确定算法:
题中的数据就像一张二维的图,上面布满了0和1,
而我们的任务是要寻找这幅图中每个0相对其最近的1的距离,这不免让我们联想图搜索算法。
观察数据规模:N,M≤182,很遗憾,我们的DFS顺利抱回8个WA!(别问我怎么知道的……)
因此,相较于DFS,本题更优秀的算法应该是:
广度优先搜索(BFS)!——层层推进
倘若,你这是你第一次接触BFS,没关系,看到最后的你自然会体悟到其妙趣~
算法需要的组件
① bool memo[1005][1005]; //储存搜索状态
② int ans[1005][1005] = { 0 }; //ans是老朋友了,答案是一张图,存放到二维数组
③ vector<pair<int, int>>v; //储存对组pair<int,int>的队列v,可谓灵魂!
④ 方向数组 //d_x、d_y配套使用,例如坐标(x+d_x[i] , y+d_[i]),i=1时,代表右平移1单位
int d_x[5] = { 0,1,-1,0,0 };
int d_y[5] = { 0,0,0,1,-1 };
⑤边界判断函数 //数组越界可不好玩哦,还是判断一下保险
bool edge(int x, int y) //保证不越界
{
if (x <= 0 || y <= 0 || x >= n + 1 || y >= m + 1)return false; //越界
return true; //不越界
}
实现
读入阶段
由于白色方块的ans默认为0,固不需要搜索,我们在读入数据阶段便进行标记:
memp[ i ][ j ]=true ; //代表不需要搜索 v.push_back(make_pair(i, j)); //导入队列
阶段效果代码如下:
memset(memo, false, sizeof(memo)); //memo初始化为false
cin >> n >> m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
cin >> a[i][j];
if(a[i][j]=='0'){ } //黑色,默认为false,未搜索过
else //白色,ans一定是0,标记为搜索过,入队
{
memo[i][j] = true; //搜索过了
v.push_back(make_pair(i, j));
}
}
搜索阶段
我们需要遍历我们的队列:v!
方向数组派上用场了!利用方向数组搜索队列元素v[ i ]的上、下、左、右四个方向,
给未搜索过的元素赋ans值,值为v[ i ]的ans值+1,因为我们一次只推进一格,
别忘了要把搜索过的元素memo值赋为true,标记为已搜索,
还要对其进行入队操作,即v.push_back(make_pair(t_x, t_y)),
这样,它就乖乖地躺在了队列的末尾,由于先来后到原则,
它会等到队列前面的元素都被遍历完后,再轮到,
反复如此,以实现“由白色点的ans=0开始,向外ans=1,ans=2……ans=n”层层推进的效果
阶段效果代码如下:
int d_x[5] = { 0,1,-1,0,0 }; //方向数组
int d_y[5] = { 0,0,0,1,-1 };
for(int i=0;i<=v.size()-1; i++) //搜索队列
{
for(int j=1;j<=4;j++) //搜索 上下左右 四个方向
{
int t_x = v[i].first + d_x[j];//target,得到判定目标的x、y坐标t_x、t_y
int t_y = v[i].second + d_y[j];
if (edge(t_x, t_y) && memo[t_x][t_y] == false) //未搜索过、未越界,搜!
{
ans[t_x][t_y] = ans[v[i].first][v[i].second] + 1;
memo[t_x][t_y] = true;
v.push_back(make_pair(t_x, t_y));
}
}
}
AC代码奉上:
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
using namespace std;
int n, m;
char a[1005][1005] = { 0 }; //读入
bool memo[1005][1005]; //储存搜索状态
int ans[1005][1005] = { 0 };
vector<pair<int, int>>v; //储存对组的队列
bool edge(int x, int y) //判断(x,y)是否越界
{
if (x <= 0 || y <= 0 || x >= n + 1 || y >= m + 1)return false; //越界
return true; //不越界
}
int main()
{
memset(memo, false, sizeof(memo)); //默认将memo全部标记为false
cin >> n >> m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
cin >> a[i][j]; //我是读入
if(a[i][j]=='0'){ } //黑色,默认为false,未搜索过
else //白色,ans一定是0,标记为搜索过,入队
{
memo[i][j] = true;
v.push_back(make_pair(i, j));
}
}
int d_x[5] = { 0,1,-1,0,0 }; //方向数组
int d_y[5] = { 0,0,0,1,-1 };
for(int i=0;i<=v.size()-1; i++) //搜索队列
for(int j=1;j<=4;j++) //搜索 上下左右 四个方向
{
int t_x = v[i].first + d_x[j];
int t_y = v[i].second + d_y[j];
if (edge(t_x, t_y) && memo[t_x][t_y] == false) //未搜索过,搜!
{
ans[t_x][t_y] = ans[v[i].first][v[i].second] + 1;
memo[t_x][t_y] = true;
v.push_back(make_pair(t_x, t_y));
}
}
for(int i=1;i<=n;i++)
{
for (int j = 1; j <= m; j++)cout << ans[i][j] << " "; //输出哈
cout << endl;
}
return 0;
}