这道题目来自第38次CSP认证考试的第二题,题目名为"机器人复健指南"。题目描述了一个机器人在n×n的棋盘上进行特定规则的移动,我们需要计算在k步内机器人能够到达的格子数量。
题目核心要素可以拆解为:
这种类型的题目在图论中被称为"广度优先搜索(BFS)的应用",因为我们需要从起点出发,逐步探索所有可能的移动路径,同时记录已经访问过的格子以避免重复计算。
对于这种"计算可达位置数量"的问题,BFS比DFS更适合,原因在于:
相比之下,DFS虽然也能解决问题,但实现起来需要考虑更多细节:
代码中使用了以下关键数据结构:
visited矩阵:n×n的二维布尔数组,记录每个格子是否已被访问q:存储待处理的格子及其步数,元素类型为pair<pair<int,int>,int>这种设计确保了:
cpp复制const int dx[8]={-2,-1,1,2,2,1,-1,-2};
const int dy[8]={1,2,2,1,-1,-2,-2,-1};
这组方向数组定义了国际象棋中马的8种可能移动方式。每组(dx[i], dy[i])对应一种移动方向,例如:
这种编码方式比写8个if语句更简洁高效。
cpp复制while(!q.empty()){
auto cur=q.front();
q.pop();
int cx=cur.first.first; //当前x
int cy=cur.first.second; //当前y
int step=cur.second;
if(step<=k){
count++;
}else{
continue;
}
// 处理8个方向...
}
这段代码实现了BFS的核心逻辑:
cpp复制if(nx>=1 && nx<=n && ny>=1 && ny<=n && !visited[nx][ny]){
visited[nx][ny]=true;
q.push({{nx,ny},step+1});
}
这部分代码确保:
ios::sync_with_stdio(false)加速IO重要提示:在BFS中,必须在节点入队时就标记为已访问,而不是在出队时。否则可能导致同一节点被多次入队,影响性能和正确性。
最坏情况下,算法需要访问棋盘上的每个格子一次,因此时间复杂度为O(n²)。但由于k的限制,实际复杂度通常小于这个上界。
主要空间消耗来自:
visited数组:O(n²)因此总空间复杂度为O(n²)。
cpp复制#include <iostream>
#include <vector>
#include <queue>
using namespace std;
// 马的8种跳跃方向
const int dx[8] = {-2,-1,1,2,2,1,-1,-2};
const int dy[8] = {1,2,2,1,-1,-2,-2,-1};
int main() {
// 加速输入输出
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, k;
cin >> n >> k;
int x, y;
cin >> x >> y;
// 访问标记数组,初始化为false
vector<vector<bool>> visited(n+1, vector<bool>(n+1, false));
// BFS队列:存储((x,y), step)
queue<pair<pair<int,int>, int>> q;
// 初始化:起点入队,标记已访问
q.push({{x,y}, 0});
visited[x][y] = true;
int count = 0;
while(!q.empty()) {
auto cur = q.front();
q.pop();
int cx = cur.first.first;
int cy = cur.first.second;
int step = cur.second;
// 步数检查
if(step > k) continue;
count++;
// 尝试8个方向
for(int i=0; i<8; i++) {
int nx = cx + dx[i];
int ny = cy + dy[i];
// 检查边界和访问状态
if(nx>=1 && nx<=n && ny>=1 && ny<=n && !visited[nx][ny]) {
visited[nx][ny] = true;
q.push({{nx,ny}, step+1});
}
}
}
cout << count << endl;
return 0;
}
输入1:
code复制5 2
3 3
解释:5×5棋盘,从(3,3)出发,最多2步
输出1:
code复制17
输入2:
code复制10 1
1 1
解释:10×10棋盘,从角落(1,1)出发,最多1步
输出2:
code复制3
输入3:
code复制1000 100
500 500
解释:大型棋盘测试
输出3:
code复制需要实际计算
这类BFS问题在现实中有广泛应用:
对于算法学习者,建议:
我在实际编码中发现,这类问题的关键在于: