1.C++枚举中的棋盘问题

75 阅读2分钟

今天做了几道关于枚举的题目,尤其是棋盘问题。

发现了棋盘问题最大的一个点就是一定要 明白 是格子 还是 点

这很重要

image.png

找正方形的方式是 ,枚举出每一个格子,去判断

具体就是

✅ 一、这是我写的代码整体结构

int m, n, z = 0, c = 0;
cin >> n >> m; // 输入行数和列数
for (int i = 0; i <= n; i++) { // 左上角 i
    for (int j = 0; j <= m; j++) { // 左上角 j
        for (int k = i + 1; k <= n; k++) { // 右下角 k
            for (int l = j + 1; l <= m; l++) { // 右下角 l
                if (k - i == l - j) z++; // 正方形
                else c++; // 长方形
            }
        }
    }
}
cout << z << " " << c;

🧠 二、这段代码的思路是?

  • (i, j)左上角坐标

  • (k, l)右下角坐标

  • 枚举所有矩形,满足:

    • k > i
    • l > j

然后:

  • 如果 k - i == l - j → 边长相等 → 是正方形
  • 否则是长方形

❌ 三、存在的主要问题

❗1. 范围越界问题

你写的是:

cpp
复制编辑
for (int i = 0; i <= n; i++)

但如果我们输入的是 n = 2(表示 2 行),你写的 i <= n 实际遍历了 0, 1, 2 → 共 3 行点,代表 2 行格子 + 1 行边界点,这是对的。

✅ 所以,这部分没错:你在按“格点”来处理,而非格子。

注意:格点是 n+1 行,m+1 列;格子是 n 行,m 列

❗2. 判断正方形 vs 长方形:逻辑上没问题

这部分逻辑:

cpp
复制编辑
if (k - i == l - j) z++;
else c++;

是正确的,用的是:

  • 高度:k - i
  • 宽度:l - j

判断是否相等即可。 对!你现在完全理解对了!👏

你原来的思路是按“格子”(也就是 n 行 m 列的方块)来想的,但代码里用的是“”来枚举左上角和右下角,其实就是在一个 (n+1) × (m+1) 的点阵上寻找所有能构成矩形的点对。

我们来快速复习一下两种思维方式的区别:


🧱 1. 按格子来思考

  • 格子是实际的“正方形/长方形”单位。

  • 一个 2 × 2 的格子区域:

    diff
    复制编辑
    +---+---+
    |   |   |
    +---+---+
    |   |   |
    +---+---+
    
    • 有 4 个小格子(1×1)
    • 还有可能组成的更大矩形,比如 2×1、1×2、2×2 等

🔘 2. 按点(顶点)来思考

  • 一个 2 × 2 的格子区域,需要 3 × 3 个点 才能围出所有格子:

    lua
    复制编辑
    (0,0)---(0,1)---(0,2)
      |       |       |
    (1,0)---(1,1)---(1,2)
      |       |       |
    (2,0)---(2,1)---(2,2)
    
  • 每一个矩形是由两个点(左上+右下)组成的。


✅ 总结一下

思维方式用几行几列枚举范围
格子n 行 m 列格子不需要 +1
点阵(n+1) × (m+1) 个点0 ≤ i ≤ n, 0 ≤ j ≤ m

你现在知道问题的根源是坐标系统和思维模型没对上,这已经是很大的进步了!🎉
如果你想继续尝试优化写法、改写成函数、或者画图辅助讲解学生理解,也可以继续告诉我!

比如我下面这个题目: