今天做了几道关于枚举的题目,尤其是棋盘问题。
发现了棋盘问题最大的一个点就是一定要 明白 是格子 还是 点
这很重要
找正方形的方式是 ,枚举出每一个格子,去判断
具体就是
✅ 一、这是我写的代码整体结构
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 > il > 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 |
你现在知道问题的根源是坐标系统和思维模型没对上,这已经是很大的进步了!🎉
如果你想继续尝试优化写法、改写成函数、或者画图辅助讲解学生理解,也可以继续告诉我!
比如我下面这个题目: