P1443 马的遍历
一道队列广搜题
此题使用队列实现,现将初始状态加入到空的队列当中;然后每次取出对首,找出队首所能转移到的状态,再将其压入队列;如此反复,这样就能保证一个状态在被访问的时候一定是采用的最短路径。
广度优先搜索的一般形式
这里是使用队列实现广度优先搜索的一般形式:
Q.push(初始状态);//将初始状态入队
while (!Q.empty()) {
State u = Q.front();//取出对首
Q.pop();//出队
for (枚举所有可扩展状态) //找到u的所有可达状态v
if (是合法的) //v需要满足某些条件,如未访问过、未在队内等
Q.push(v);//入队(同时可能需要维护某些必要信息)
}
就本题而言,先建立一个结构体数组用于存储扩展的节点。先让起点入队,然后在队列取状态逐个扩展。容易被证明每个点被扩展到时一定是最小步数。复杂度是O(mn)
代码实现
#include <cstdio>
#include <queue>
#include <cstring>
#define maxn 310
using namespace std;
struct Node {
int x, y;
};
queue<Node> Q;
int ans[maxn][maxn];
int walk[8][2] = {{2, 1}, {1, 2}, {-1, 2}, {-2, 1}, {-2, -1}, {-1, -2}, {1, -2}, {2, -1}, };
int main() {
int n, m, sx, sy;
memset(ans, -1, sizeof(ans));
scanf("%d %d %d %d", &n, &m, &sx, &sy);
Node tmp = {sx, sy};
Q.push(tmp);
ans[sx][sy] = 0;
while(!Q.empty()) {
Node u = Q.front();
int ux = u.x, uy = u.y;
Q.pop();
for (int k = 0; k < 8; ++k) {
int x = ux + walk[k][0];
int y = uy + walk[k][1];
int d = ans[ux][uy];
if (x < 1 || x > n || y < 1 || y > m || ans[x][y] != -1) continue;
ans[x][y] = d + 1;
Node tmp = {x, y};
Q.push(tmp);
}
}
for (int i = 1; i <= n; ++i, puts("")) {
for (int j = 1; j <= m; ++j)
printf("%-5d", ans[i][j]);
}
return 0;
}