【发布时间】:2021-03-11 15:25:49
【问题描述】:
我的作业有问题。我写了一个代码,但它在某些输入上给出了错误的答案(我看不到输入)。但是,该代码适用于我尝试的所有示例。
这就是问题所在。
机器人将邮件投递到 X 的各个角落。X 国可以表示为一个 N × M 字段,其中每个单元格要么可交叉(表示为“.”)或不可交叉(“#”)。 从当前单元格开始,机器人只能移动到相邻单元格。机器人也需要转弯,例如,如果机器人向右走,并且需要向上移动,他首先向左转弯。同样,它可以向右转。机器人的开发人员还提供了与当前方向相反的方向转弯。计算最短路径时没有考虑转弯,因为机器人很容易做到这一点。 由于故障,机器人在左转后不能再左转,直到右转,反之亦然。转身是独立进行的,不会影响此规则,但是,机器人在同一个单元格中不能转超过一圈。你被指派为机器人编写一个修改过的程序,以便它可以计算出现此故障的最短路径。
输入示例:
5 5 // N and M
#...# // grid
..#.#
..#.#
..#.#
#....
2 2 // source
2 4 // destination
输出应包含最短路径的长度和最短路径本身(如果没有最短路径,则为“-1”)。保证源和目标是可以通过的。您可以在第一步之前将机器人转向任何方向。
这就是我所做的。我为每个单元格计算了具有 12 个节点的图形(一个用于方向(上/下/左/右)和可用移动(左/右/两者)的每种组合)。使用堆栈实现 BFS(最初堆栈中有 2 个顶点,一个用于源(上 + 两者),一个用于(左 + 两者))。如果 BFS 到达与目的地对应的 12 个节点之一,则 BFS 停止。
我的代码:
#include <algorithm>
#include <iostream>
#include <vector>
#include <list>
#include <utility>
class Graph {
public:
std::vector<std::vector<int>> adjacent_;
int number_of_vertices_;
explicit Graph(int number_of_vertices);
void AddEdge(int first_vertex, int second_vertex) {
adjacent_[first_vertex].emplace_back(second_vertex);
}
};
Graph::Graph(int number_of_vertices) {
number_of_vertices_ = number_of_vertices;
std::vector<std::vector<int>> adjacent(number_of_vertices);
adjacent_ = adjacent;
}
enum Looks { UP = 0, DOWN = 3, LEFT = 6, RIGHT = 9 };
enum Moves { L = 0, R = 1, LR = 2 };
void MovesRight(int row, int column, int number_of_columns, Graph &map) {
int rows_in_map = 12 * row;
map.AddEdge((rows_in_map + UP + R) * number_of_columns + column,
(rows_in_map + RIGHT + L) * number_of_columns + column + 1);
map.AddEdge((rows_in_map + UP + LR) * number_of_columns + column,
(rows_in_map + RIGHT + L) * number_of_columns + column + 1);
map.AddEdge((rows_in_map + RIGHT + R) * number_of_columns + column,
(rows_in_map + RIGHT + R) * number_of_columns + column + 1);
map.AddEdge((rows_in_map + RIGHT + LR) * number_of_columns + column,
(rows_in_map + RIGHT + LR) * number_of_columns + column + 1);
map.AddEdge((rows_in_map + RIGHT + L) * number_of_columns + column,
(rows_in_map + RIGHT + L) * number_of_columns + column + 1);
map.AddEdge((rows_in_map + LEFT + R) * number_of_columns + column,
(rows_in_map + RIGHT + R) * number_of_columns + column + 1);
map.AddEdge((rows_in_map + LEFT + LR) * number_of_columns + column,
(rows_in_map + RIGHT + LR) * number_of_columns + column + 1);
map.AddEdge((rows_in_map + LEFT + L) * number_of_columns + column,
(rows_in_map + RIGHT + L) * number_of_columns + column + 1);
map.AddEdge((rows_in_map + DOWN + L) * number_of_columns + column,
(rows_in_map + RIGHT + R) * number_of_columns + column + 1);
map.AddEdge((rows_in_map + DOWN + LR) * number_of_columns + column,
(rows_in_map + RIGHT + R) * number_of_columns + column + 1);
}
void MovesLeft(int row, int column, int number_of_columns, Graph &map) {
int rows_in_map = 12 * row;
map.AddEdge((rows_in_map + UP + L) * number_of_columns + column,
(rows_in_map + LEFT + R) * number_of_columns + column - 1);
map.AddEdge((rows_in_map + UP + LR) * number_of_columns + column,
(rows_in_map + LEFT + R) * number_of_columns + column - 1);
map.AddEdge((rows_in_map + RIGHT + R) * number_of_columns + column,
(rows_in_map + LEFT + R) * number_of_columns + column - 1);
map.AddEdge((rows_in_map + RIGHT + LR) * number_of_columns + column,
(rows_in_map + LEFT + LR) * number_of_columns + column - 1);
map.AddEdge((rows_in_map + RIGHT + L) * number_of_columns + column,
(rows_in_map + LEFT + L) * number_of_columns + column - 1);
map.AddEdge((rows_in_map + LEFT + R) * number_of_columns + column,
(rows_in_map + LEFT + R) * number_of_columns + column - 1);
map.AddEdge((rows_in_map + LEFT + LR) * number_of_columns + column,
(rows_in_map + LEFT + LR) * number_of_columns + column - 1);
map.AddEdge((rows_in_map + LEFT + L) * number_of_columns + column,
(rows_in_map + LEFT + L) * number_of_columns + column - 1);
map.AddEdge((rows_in_map + DOWN + R) * number_of_columns + column,
(rows_in_map + RIGHT + L) * number_of_columns + column - 1);
map.AddEdge((rows_in_map + DOWN + LR) * number_of_columns + column,
(rows_in_map + RIGHT + L) * number_of_columns + column - 1);
}
void MovesUp(int row, int column, int number_of_columns, Graph &map) {
int rows_in_map = 12 * row;
map.AddEdge((rows_in_map + UP + L) * number_of_columns + column,
(rows_in_map - 12 + UP + L) * number_of_columns + column);
map.AddEdge((rows_in_map + UP + LR) * number_of_columns + column,
(rows_in_map - 12 + UP + LR) * number_of_columns + column);
map.AddEdge((rows_in_map + UP + R) * number_of_columns + column,
(rows_in_map - 12 + UP + R) * number_of_columns + column);
map.AddEdge((rows_in_map + RIGHT + L) * number_of_columns + column,
(rows_in_map - 12 + UP + R) * number_of_columns + column);
map.AddEdge((rows_in_map + RIGHT + LR) * number_of_columns + column,
(rows_in_map - 12 + UP + R) * number_of_columns + column);
map.AddEdge((rows_in_map + LEFT + R) * number_of_columns + column,
(rows_in_map - 12 + UP + L) * number_of_columns + column);
map.AddEdge((rows_in_map + LEFT + LR) * number_of_columns + column,
(rows_in_map - 12 + UP + L) * number_of_columns + column);
map.AddEdge((rows_in_map + DOWN + L) * number_of_columns + column,
(rows_in_map - 12 + UP + L) * number_of_columns + column);
map.AddEdge((rows_in_map + DOWN + LR) * number_of_columns + column,
(rows_in_map - 12 + UP + LR) * number_of_columns + column);
map.AddEdge((rows_in_map + DOWN + R) * number_of_columns + column,
(rows_in_map - 12 + UP + R) * number_of_columns + column);
}
void MovesDown(int row, int column, int number_of_columns, Graph &map) {
int rows_in_map = 12 * row;
map.AddEdge((rows_in_map + UP + L) * number_of_columns + column,
(rows_in_map + 12 + DOWN + L) * number_of_columns + column);
map.AddEdge((rows_in_map + UP + LR) * number_of_columns + column,
(rows_in_map + 12 + DOWN + LR) * number_of_columns + column);
map.AddEdge((rows_in_map + UP + R) * number_of_columns + column,
(rows_in_map + 12 + DOWN + R) * number_of_columns + column);
map.AddEdge((rows_in_map + RIGHT + R) * number_of_columns + column,
(rows_in_map + 12 + DOWN + L) * number_of_columns + column);
map.AddEdge((rows_in_map + RIGHT + LR) * number_of_columns + column,
(rows_in_map + 12 + DOWN + L) * number_of_columns + column);
map.AddEdge((rows_in_map + LEFT + L) * number_of_columns + column,
(rows_in_map + 12 + DOWN + R) * number_of_columns + column);
map.AddEdge((rows_in_map + LEFT + LR) * number_of_columns + column,
(rows_in_map + 12 + DOWN + R) * number_of_columns + column);
map.AddEdge((rows_in_map + DOWN + L) * number_of_columns + column,
(rows_in_map + 12 + DOWN + L) * number_of_columns + column);
map.AddEdge((rows_in_map + DOWN + LR) * number_of_columns + column,
(rows_in_map + 12 + DOWN + LR) * number_of_columns + column);
map.AddEdge((rows_in_map + DOWN + R) * number_of_columns + column,
(rows_in_map + 12 + DOWN + R) * number_of_columns + column);
}
void MakeGraph(int number_of_rows, int number_of_columns,
std::vector<std::vector<char>> &grid, Graph &map) {
for (int row = 0; row < number_of_rows; ++row) {
for (int column = 0; column < number_of_columns; ++column) {
std::cin >> grid[row][column];
}
}
for (int row = 0; row < number_of_rows; ++row) {
for (int column = 0; column < number_of_columns; ++column) {
if (column + 1 < number_of_columns) {
if (grid[row][column] == '.' && grid[row][column + 1] == '.') {
MovesRight(row, column, number_of_columns, map);
}
}
if (0 < column) {
if (grid[row][column] == '.' && grid[row][column - 1] == '.') {
MovesLeft(row, column, number_of_columns, map);
}
}
if (0 < row) {
if (grid[row][column] == '.' && grid[row - 1][column] == '.') {
MovesUp(row, column, number_of_columns, map);
}
}
if (row + 1 < number_of_rows) {
if (grid[row][column] == '.' && grid[row + 1][column] == '.') {
MovesDown(row, column, number_of_columns, map);
}
}
}
}
}
int BFS(Graph &map, int source, int destination,
std::vector<int> &predecessor, std::vector<int> &distance,
int number_of_columns) {
std::list<int> queue;
std::vector<bool> visited(map.number_of_vertices_, false);
visited[source + (UP + LR) * number_of_columns] = true;
distance[source + (UP + LR) * number_of_columns] = 0;
queue.push_back(source + (UP + LR) * number_of_columns);
visited[source + (LEFT + LR) * number_of_columns] = true;
distance[source + (LEFT + LR) * number_of_columns] = 0;
queue.push_back(source + (LEFT + LR) * number_of_columns);
while (!queue.empty()) {
int vertex;
vertex = queue.front();
queue.pop_front();
for (size_t counter = 0; counter < map.adjacent_[vertex].size(); ++counter) {
int current_vertex = map.adjacent_[vertex][counter];
if (!visited[current_vertex]) {
visited[current_vertex] = true;
distance[current_vertex] = distance[vertex] + 1;
predecessor[current_vertex] = vertex;
queue.push_back(current_vertex);
if ((current_vertex / (12 * number_of_columns)) * (12 * number_of_columns)
+ (current_vertex % number_of_columns) == destination) {
return current_vertex;
}
}
}
}
return -1;
}
void printShortestDistance(Graph &map, int source,
int destination, int number_of_columns) {
std::vector<int> predecessor(map.number_of_vertices_, -1);
std::vector<int> distance(map.number_of_vertices_, 10000000);
int result = BFS(map, source, destination, predecessor, distance,
number_of_columns);
if (result == -1) {
std::cout << -1 << "\n";
} else {
std::cout << distance[result] << "\n";
int current_vertex = result;
std::vector<std::pair<int, int>> path;
while (current_vertex != -1) {
path.emplace_back(((current_vertex / number_of_columns) / 12) + 1,
(current_vertex % number_of_columns) + 1);
current_vertex = predecessor[current_vertex];
}
for (size_t i = 0; i < path.size(); ++i) {
std::cout << path[path.size() - 1 - i].first << " "<<
path[path.size() - 1 - i].second << "\n";
}
}
}
int main() {
std::ios_base::sync_with_stdio(false);
std::cin.tie(nullptr);
int number_of_rows, number_of_columns;
std::cin >> number_of_rows >> number_of_columns;
std::vector<std::vector<char>> grid(number_of_rows,
std::vector<char>(number_of_columns));
Graph map(12 * number_of_rows * number_of_columns);
MakeGraph(number_of_rows, number_of_columns, grid, map);
int first_row, second_row, first_column, second_column;
std::cin >> first_row >> first_column >> second_row >> second_column;
--first_row;
--first_column;
--second_row;
--second_column;
int source = 12 * first_row * number_of_columns + first_column;
int destination = 12 * second_row * number_of_columns + second_column;
printShortestDistance(map, source, destination, number_of_columns);
return 0;
}
您能否告诉我在我的实现中出了什么问题,或者就哪些输入可能会失败提供一些想法?
【问题讨论】:
-
你尝试过更复杂的测试用例吗?像源 = 1 3 和目的地 5 5 还是其他地图?
-
@Surt 是的,当然,我尝试了多个不同的地图,但找不到一个给出错误答案的地图。我想我不擅长制作迷宫。
-
在您的 BFS 中,您将两个顶点添加到队列中,如何以及为什么选择它们?
-
@Surf 机器人朝上的第一个顶点可以左右转向,机器人朝左的第二个顶点可以左右转向。这是因为机器人最初可以面向任何方向(其他两个方向仍然考虑,因为机器人可以转身)。
标签: c++ algorithm breadth-first-search shortest-path