题解 | 量子网络穿梭(BFS)
量子网络穿梭
https://www.nowcoder.com/practice/1352032ab7744c148577c0d05eff841b
C++版本
// C++版本
#include <iostream>
#include <queue>
#include <vector>
// 路的类型
enum class Road : char {
START = 'S',
END = 'E',
WALL = '1',
GATE = '2',
};
// 坐标类型
struct Point {
int x, y;
Point() = delete;
Point(const int _x, const int _y) : x(_x), y(_y) {}
Point operator+(const Point& _p) const { return {x + _p.x, y + _p.y}; }
bool operator==(const Point& _p) const { return x == _p.x && y == _p.y; }
bool operator!=(const Point& _p) const { return !operator==(_p); }
~Point() = default;
};
// 二维矩阵类型
template<typename T>
using grid_t = std::vector<std::vector<T>>;
// 能否可走判断
inline bool cango(const grid_t<char>& g, const Point& p, const grid_t<int>& d) {
const int m = static_cast<int>(g.size());
const int n = static_cast<int>(g[0].size());
return p.x >= 0 && p.x < m && p.y >= 0 && p.y < n && g[p.x][p.y] != static_cast<char>(Road::WALL) && d[p.x][p.y] == -1;
}
// 广度优先遍历
int bfs(const grid_t<char>& grid, const Point& start, const Point& end, const std::vector<Point>& gates) {
const int m = static_cast<int>(grid.size());
const int n = static_cast<int>(grid[0].size());
std::queue<Point> queue; // BFS 辅助队列
grid_t<int> distance(m, std::vector<int>(n, -1)); // 记录到达每个位置的最短时间
const std::vector<Point> directions = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}}; // 方向
// 广度优先遍历
queue.push(start);
distance[start.x][start.y] = 0;
while (!queue.empty()) {
Point current = queue.front();
queue.pop();
if (current == end) break; // 到达终点
// 试探四个方向
for (const Point& direction : directions) {
Point next = current + direction; // 尝试移动
if (!cango(grid, next, distance)) continue;
// 1. 尝试传送门:所有传送门走一遍(没访问过的才能走)
if (grid[next.x][next.y] == static_cast<char>(Road::GATE)) {
for (const Point& gate : gates) {
distance[gate.x][gate.y] = distance[current.x][current.y] + 1;
queue.push(gate);
}
} else { // 2. 尝试普通的路:没走过的相邻的路走一遍
distance[next.x][next.y] = distance[current.x][current.y] + 1;
queue.push(next);
}
}
}
return distance[end.x][end.y];
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int m, n; // 地图尺寸
std::cin >> m >> n;
grid_t<char> grid(m, std::vector<char>(n)); // 地图信息
Point start(0, 0), end(0, 0); // 起点和终点坐标
std::vector<Point> gates; // 传送门坐标
// 记录特殊位置
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
std::cin >> grid[i][j];
if (grid[i][j] == static_cast<char>(Road::WALL) || grid[i][j] == '\n') continue;
if (grid[i][j] == static_cast<char>(Road::START)) {
start = {i, j};
} else if (grid[i][j] == static_cast<char>(Road::END)) {
end = {i, j};
} else if (grid[i][j] == static_cast<char>(Road::GATE)) {
gates.emplace_back(i, j);
}
}
}
std::cout << bfs(grid, start, end, gates) << std::endl;
return 0;
}
C语言版本
// C语言版本
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
// 地图尺寸
#define GRID_MAX_SIZE 50
// 传送门最大数量
#define GATE_MAX_COUNT 4
typedef struct Point Point;
typedef struct Queue Queue;
// 路的类型
enum Road {
START = 'S',
END = 'E',
WALL = '1',
GATE = '2',
};
// 坐标类型
struct Point {
int x, y;
};
// 数组队列结构
struct Queue {
Point data[(GRID_MAX_SIZE * GRID_MAX_SIZE) / 2];
unsigned int front;
unsigned int back;
unsigned int size;
};
// 队列初始化
void queue_init(Queue *queue) {
queue->front = 0;
queue->back = 0;
queue->size = 0;
}
// 入队
void queue_push(Queue *queue, Point *point) {
if (queue->size < GRID_MAX_SIZE * GRID_MAX_SIZE) {
queue->data[queue->back++] = *point;
queue->size++;
if (queue->back == GRID_MAX_SIZE * GRID_MAX_SIZE) queue->back = 0;
}
}
// 出队
void queue_pop(Queue *queue, Point *point) {
if (queue->size > 0) {
*point = queue->data[queue->front++];
queue->size--;
if (queue->front == GRID_MAX_SIZE * GRID_MAX_SIZE) queue->front = 0;
}
}
// 是否可走
bool cango(int m, int n, char (*grid)[GRID_MAX_SIZE], int (*d)[GRID_MAX_SIZE], Point *p) {
return p->x >= 0 && p->x < m && p->y >= 0 && p->y < n && grid[p->x][p->y] != WALL && d[p->x][p->y] == -1;
}
// 广度优先遍历
int bfs(int m, int n, char (*grid)[GRID_MAX_SIZE], Point *start, Point *end, int gate_count, Point *gates) {
Queue queue;
queue_init(&queue);
int distance[GRID_MAX_SIZE][GRID_MAX_SIZE];
Point directions[4] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
// 初始化 distance
memset(distance, -1, sizeof(distance));
distance[start->x][start->y] = 0;
queue_push(&queue, start);
while (queue.size) {
Point current;
queue_pop(&queue, ¤t);
if (current.x == end->x && current.y == end->y) break; // 到达终点
// 试探四个方向
for (unsigned int i = 0; i < 4; ++i) {
Point next = {current.x + directions[i].x, current.y + directions[i].y};
if (!cango(m, n, grid, distance, &next)) continue;
// 1. 尝试所有传送门(未走过的)
if (grid[next.x][next.y] == GATE) {
for (unsigned int j = 0; j < gate_count; ++j) {
if (distance[gates[j].x][gates[j].y] == -1) {
distance[gates[j].x][gates[j].y] = distance[current.x][current.y] + 1;
queue_push(&queue, &gates[j]);
}
}
} else { // 2. 尝试相邻的所有普通路(未走过的)
distance[next.x][next.y] = distance[current.x][current.y] + 1;
queue_push(&queue, &next);
}
}
}
return distance[end->x][end->y];
}
int main() {
int m, n;
scanf("%d %d", &m, &n);
getchar(); // 清除换行符
char grid[GRID_MAX_SIZE][GRID_MAX_SIZE]; // 地图信息
Point start, end; // 起点和终点
Point gates[GATE_MAX_COUNT]; // 传送门位置信息
unsigned int gate_count = 0; // 传送门数量
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
grid[i][j] = getchar();
if (grid[i][j] == WALL) continue;
if (grid[i][j] == START) {
start = (Point){i, j};
} else if (grid[i][j] == END) {
end = (Point){i, j};
} else if (grid[i][j] == GATE) {
gates[gate_count++] = (Point){i, j};
}
}
getchar(); // 清除换行符
}
printf("%d\n", bfs(m, n, grid, &start, &end, gate_count, gates));
return 0;
}
#华为机考#