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;
}
原文地址:https://www.cnblogs.com/Kyriech-Francis/p/Answer_P1143.html