读入数据到map,比如说map[i][j],由于是一行一行读入的,所以 i 代表行, j 代表列,而且还是从0开始的(看习惯,我喜欢从0开始),比如map[1][2]就是第2行第3列
题目要求,比如说
小雪人初始在左上角(即单元格(0, 0)),小雪人的家在右下角(即单元格(M – 1, N - 1))
那么其坐标系就是第一个数为行,第二个数为列,但是也不好说,因为后面的样例都是正方形,我怎么知道哪个是行,哪个是列。看了看24年的,里面明确说了,第一维为行,第二维为列,那么我们就按照这个标准去做。
for (int i = 0; i < M; ++i) { // i 是行号 (对应 y 轴)
for (int j = 0; j < N; ++j) { // j 是列号 (对应 x 轴)
// --- 计算当前格子的屏幕坐标 ---
// x = 左边距 + 列号 * 格子宽
// y = 顶边距 + 行号 * 格子高
int x = leftMargin + j * cellWidth;
int y = topMargin + i * cellHeight;
基于此,我建议绘图部分用xy,管理部分用row和col,或者rc,方便区分
以下主要是针对模板代码里面的dfs,尤其是里面的方向数组:
这是一个非常经典且容易混淆的问题!在编程(特别是涉及矩阵、图像处理、地图网格)时,x 和 y 的定义经常会打架。
在你的这个代码语境下(以及大多数 C++ 算法题解中):x 代表行 (Row),y 代表列 (Column)。
这与我们在数学课上学的“直角坐标系”是相反的。让我为你彻底拆解一下:
1. 为什么会混淆?
-
数学/屏幕坐标系:
- 轴:水平向右(代表列)。
- 轴:垂直向下(代表行)。
- 坐标表示: 通常指 (列, 行)。
-
数组/矩阵索引(编程习惯):
- 二维数组定义:
map[行][列]即map[row][col]。 - 程序员习惯:为了对应数组写法,通常把第一个下标叫
x,第二个下标叫y。 - 坐标表示:
map[x][y]实际上是 (第 x 行, 第 y 列)。
- 二维数组定义:
2. 在你的代码中
看看你定义的方向数组:
// 下, 右, 上, 左
int dx[] = {1, 0, -1, 0};
int dy[] = {0, 1, 0, -1};我们来验证一下:
- 向下移动:意味着行号增加,列号不变。
- 代码里:
dx = 1(行+1),dy = 0(列不动)。 符合“x是行”。
- 代码里:
- 向右移动:意味着行号不变,列号增加。
- 代码里:
dx = 0(行不动),dy = 1(列+1)。 符合“y是列”。
- 代码里:
3. 图解记忆法
请记住这个对应关系,这是算法题里的“潜规则”:
(y轴 / 列 col)
0 1 2 3 ...
+---+---+---+---+
0 | | | | |
+---+---+---+---+
1 | | | | | <-- x轴 (行 row)
+---+---+---+---+
2 | | | | |
+---+---+---+---+
...
- x 控制 上下 移动(变化的是行号)。
- y 控制 左右 移动(变化的是列号)。
- 访问方式:
grid[x][y]
4. 这里的 QPoint 是个大坑!
注意! Qt 的 QPoint 使用的是屏幕坐标系!
QPoint(a, b)中:a是 x坐标 (水平/列)。b是 y坐标 (垂直/行)。
如果你在 DFS 算法里把 x 当作行,y 当作列,那么在使用 QPoint 存结果时,必须反过来写:
// 假设你的 dfs(x, y) 中,x是行,y是列
resultPath.push_back(QPoint(y, x));
// QPoint(水平x, 垂直y) = QPoint(列, 行)或者,为了避免精神分裂,我建议你在 DFS 里直接改变量名,不要叫 x, y,叫 r, c:
// 推荐写法:r (row), c (col)
int dr[] = {1, 0, -1, 0}; // 行变化
int dc[] = {0, 1, 0, -1}; // 列变化
bool dfs(int r, int c, ...) {
// ...
int nextR = r + dr[i];
int nextC = c + dc[i];
// ...
// 存入 QPoint 时,QPoint(x, y) 对应 QPoint(列, 行)
resultPath.push_back(QPoint(c, r));
}总结:
在你的那段 dx/dy 代码里,x = 行,y = 列。如果你不改变量名,请务必记住:x 变了是上下走,y 变了是左右走。