C++题解:【入门】快乐的马里奥(BFS)
描述
马里奥是一个快乐的油漆工人,这天他接到了一个油漆任务,要求马里奥把一个 n 行 m 列的矩阵每一格都用油漆标记一个数字,标记的顺序按照广度优先搜索的方式进行,也就是他会按照如下方式标记:
1 、首先标记第 1 行第 1 列的单元格,标记数字为 1 ;
2 、然后标记当前单元格上下左右四个方向所有能标记的单元格,且:
① 标记顺序按照:右、下、左、上的优先级;
② 不能标记到矩阵外,且标记过的数字不能重复标记;
3 、当本单元格标记结束,寻找比本单元格中数字大 1 的单元格,标记那个单元格的上下左右四个方向,也是按照步骤 2 所示的要求进行标记。
依次类推,直到所有单元格都被标记。
比如:如果有一个3 * 3 的矩阵如下,那么首先标记 1,1 单元格,并按照上面步骤 2 的要求标记其四周能够标记的单元格,标记结果如下:
接下来,标记比 1,1 格大 1 的数字的四周的单元格,也就是标记值为 2 的单元格四周的单元格,标记结果如下:
接下来标记值为 3 的单元格四周的单元格,标记结果如下:
接下来标记值为 4 的单元格四周的单元格,标记结果如下:
接下来标记值为 5 的单元格四周的单元格,标记结果如下:
接下来标记值为 6 的单元格四周的单元格,但这个数字四周的单元格已经被标记,因此继续标记值为7四周的单元格,标记结果如下:
此时,发现标记结束,得到如上图所示的标记结果。
输入描述
两个整数 n 和 m , n 和 m 都是 3~100 之间的整数。
输出描述
输出 n 行 m 列的标记后的矩阵,输出每个数后空一格。
用例输入 1
3 3
用例输出 1
1 2 4 3 5 7 6 8 9
来源
广搜
AC CODE
#include<bits/stdc++.h>
using namespace std;int a[110][110],q[10100][3];int fx[5]={0,0,1,0,-1};
int fy[5]={0,1,0,-1,0};
int tx,ty;
int k=1;
int n,m,i,j;int head=1,tail=1;int main()
{cin>>n>>m;a[1][1]=k;k++;q[1][1]=1;q[1][2]=1;while(head<=tail){for(i=1;i<=4;i++){tx=q[head][1]+fx[i];ty=q[head][2]+fy[i];if(tx>=1&&tx<=n&&ty>=1&&ty<=m&&a[tx][ty]==0){tail++;q[tail][1]=tx;q[tail][2]=ty;a[tx][ty]=k;k++;}} head++; } for(i=1;i<=n;i++){for(j=1;j<=m;j++){cout<<a[i][j]<<" ";}cout<<endl;} return 0;}
题目详解
一、问题核心理解
这道题要求我们使用广度优先搜索(BFS)对n×m矩阵进行数字标记,核心规则是:
• 从(1,1)位置开始标记为1
• 按"右、下、左、上"的优先级顺序标记相邻未访问格子
• 每次处理完当前层级,按数字递增顺序处理下一层级
二、代码整体架构
代码采用经典BFS实现,主要包含:
• 矩阵存储结构 a[110][110]
• 队列结构 q[10100][3] 用于BFS遍历
• 方向数组 fx[] 和 fy[] 定义搜索顺序
三、关键代码详解
1. 方向数组设计
int fx[5]={0,0,1,0,-1}; // x方向偏移量
int fy[5]={0,1,0,-1,0}; // y方向偏移量
• 索引1-4对应"右、下、左、上"四个方向
• 偏移量设计:
◦ 右:(0,1) 列+1
◦ 下:(1,0) 行+1
◦ 左:(0,-1) 列-1
◦ 上:(-1,0) 行-1
2. 初始化操作
cin>>n>>m;
a[1][1]=k; // 起点(1,1)标记为1
k++; // 下一个标记值准备q[1][1]=1; // 起点入队
q[1][2]=1;
• 矩阵下标从1开始,符合题目习惯
• 队列初始存入起点坐标(1,1)
3. BFS核心逻辑
while(head<=tail) // 队列非空时循环
{for(i=1;i<=4;i++) // 按优先级遍历四个方向{tx=q[head][1]+fx[i]; // 计算新坐标ty=q[head][2]+fy[i];// 检查坐标合法性和是否已标记if(tx>=1&&tx<=n&&ty>=1&&ty<=m&&a[tx][ty]==0){tail++; // 队列尾指针后移q[tail][1]=tx; // 新坐标入队q[tail][2]=ty;a[tx][ty]=k; // 标记当前格子k++; // 标记值递增}}head++; // 处理完当前节点,队头指针后移
}
• 队列采用"头进头出"的BFS标准模式
• 每个节点出队时,按优先级检查四个方向
• 合法新节点入队并标记,保证按层次遍历
4. 结果输出
for(i=1;i<=n;i++)
{for(j=1;j<=m;j++){cout<<a[i][j]<<" ";}cout<<endl;
}
• 按行优先顺序输出矩阵
• 每个数字后加空格,符合题目格式要求
四、算法执行过程分析
以3×3矩阵为例:
1. 初始队列:[(1,1)],标记a[1][1]=1
2. 处理队头(1,1),按顺序检查四个方向:
◦ 右(1,2)合法,标记为2并入队
◦ 下(2,1)合法,标记为3并入队
◦ 左(1,0)越界,跳过
◦ 上(0,1)越界,跳过
此时队列:[(1,2),(2,1)]
3. 处理队头(1,2),检查方向:
◦ 右(1,3)合法,标记为4并入队
◦ 下(2,2)合法,标记为5并入队
◦ 左(1,1)已标记,跳过
◦ 上(0,2)越界,跳过
队列更新:[(2,1),(1,3),(2,2)]
4. 以此类推,最终得到题目要求的标记结果
五、算法复杂度分析
• 时间复杂度:O(n×m),每个格子最多入队一次
• 空间复杂度:O(n×m),队列和矩阵存储需求
• 优化点:队列大小设为10100,足够容纳100×100矩阵的所有格子
六、总结
该代码通过标准BFS实现了题目要求的矩阵标记逻辑,核心在于:
1. 方向数组的优先级顺序设计
2. 队列的正确入队出队操作
3. 矩阵边界和已标记状态的检查
这种BFS遍历方式保证了每个格子按层次顺序被标记,完美符合题目要求的"广度优先搜索"规则。