N×M棋盘正方形与长方形个数计算(公式法与代码实现)
好的,这是一个很经典的棋盘计数问题。核心在于理解长方形和正方形的计数方式,并利用数学公式来高效计算,避免复杂的循环遍历(尤其是在N和M最大为100时,虽然循环也能过,但公式法更快更优雅)。 下面我来为你详细解析。 ### 💡 核心思路:从组合数学出发 棋盘是由横线和竖线构成的。一个 **矩形** (包括正方形和长方形) 在棋盘上可以由它的“四条边”来确定:上边、下边、左边、右边。 * **上边和下边的选择**:从 `N+1` 条横线中选出2条。 * **左边和右边的选择**:从 `M+1` 条竖线中选出2条。 选择的每一种组合,都对应棋盘上的一个唯一的矩形。 **总矩形数 (包括正方形和长方形)** = \( C(N+1, 2) \times C(M+1, 2) \) 其中 \( C(n, 2) = \frac{n \times (n-1)}{2} \) 是组合数。 ### 🤔 区分正方形和长方形 1. **计算所有正方形的个数**: * 一个边长为 `min(N, M)` 的正方形,它可以出现在棋盘上的不同位置。 * 更具体地,对于一个边长为 `k` (`1 ≤ k ≤ min(N, M)`) 的正方形: * 它在垂直方向上的可能起始位置有 \( N - k + 1 \) 个。 * 它在水平方向上的可能起始位置有 \( M - k + 1 \) 个。 * 所有边长为 `k` 的正方形的个数为:\( (N - k + 1) \times (M - k + 1) \)。 * 遍历 `k` 从 1 到 `min(N, M)`,累加即可得到总的正方形数量。 2. **计算长方形的个数 (不包括正方形)**: * 非常简单:**长方形个数 = 总矩形数 - 正方形个数**。 ### 📝 输入输出示例 * **输入**: `N=3, M=2` * **计算过程**: * 总矩形数: `C(4, 2) * C(3, 2) = 6 * 3 = 18` * 正方形数: * k=1: `(3-1+1) * (2-1+1) = 3 * 2 = 6` * k=2: `(3-2+1) * (2-2+1) = 2 * 1 = 2` * 总正方形数 = `6 + 2 = 8` * 长方形数 = `18 - 8 = 10` * **输出**: `8, 10` (与题目示例一致) ### 💻 代码实现 (Python) 这个解法非常高效,时间复杂度为 \( O(\min(N, M)) \),空间复杂度为 \( O(1) \)。 ```python def count_shapes(N, M): """ 计算 N x M 棋盘中的正方形和长方形个数。 Args: N: 棋盘的行数 (1 <= N <= 100) M: 棋盘的列数 (1 <= M <= 100) Returns: tuple: (正方形个数, 长方形个数) """ # 1. 计算总的矩形个数 (包含正方形) # 组合数 C(n, 2) = n*(n-1)/2 total_rectangles = (N * (N + 1) // 2) * (M * (M + 1) // 2) # 2. 计算所有正方形的个数 total_squares = 0 # 最大可能的正方形边长 max_side = min(N, M) for k in range(1, max_side + 1): # 边长为 k 的正方形个数 count_k_square = (N - k + 1) * (M - k + 1) total_squares += count_k_square # 3. 计算长方形的个数 total_rectangles_not_square = total_rectangles - total_squares return total_squares, total_rectangles_not_square # 主程序 if __name__ == "__main__": # 输入格式:N, M (注意题目要求是用逗号分隔) # 这里我们提供两种常见输入方式,实际可根据平台要求调整 # 方式一:假设输入是一行,以空格或逗号分隔 try: input_str = input().strip() # 处理逗号或空格作为分隔符 if ',' in input_str: parts = input_str.split(',') else: parts = input_str.split() N = int(parts[0]) M = int(parts[1]) except: # 方式二:假设是两行输入 N = int(input().strip()) M = int(input().strip()) squares, rects = count_shapes(N, M) # 输出格式:正方形的个数与长方形的个数,用逗号隔开 print(f"{squares}, {rects}") ``` ### 🛠️ 关键代码解释 * `N * (N + 1) // 2`:这其实是 `C(N+1, 2)` 的另一种写法。因为 \( C(n, 2) = \frac{n(n-1)}{2} \),当 \( n = N+1 \) 时,就是 `(N+1)*N/2`。这里用整数除法 `//` 保证结果为整数。 * `max_side = min(N, M)`:正方形的边长不能超过棋盘较短的边。 * `range(1, max_side + 1)`:遍历所有可能的边长。 * `(N - k + 1) * (M - k + 1)`:这是计算边长为 `k` 的正方形在棋盘上能有多少个位置的核心公式。 * `total_rectangles_not_square`:这里用一个清晰的变量名来表示“非正方形的长方形”。 ### 📝 输入处理说明 题目中给的输入格式是 `N,M`,即用逗号分隔。代码中已经处理了这种情况,同时也兼容空格分隔或分多行输入,以增强鲁棒性。 ### 💎 与扩展建议 1. **公式法的优势**:对于 `N=100, M=100`,循环只需要执行 `min(100,100)=100` 次,非常快。而如果用四重循环(遍历左上角和右下角)去暴力枚举,时间复杂度会是 \( O(N^2 M^2) \),在N=100时就已经上是 \( 10^8 \) 量级,可能会超时。 2. **理解组合意义**:理解“在`N+1`条横线中选2条”是解决这类棋盘/网格矩形问题的关键。一旦掌握,很多变种问题(如计算带障碍物的棋盘)也能找到思路。 3. **测试边界**: * `N=1, M=1`:只有一个正方形,总矩形也是1。结果是 `1, 0`。 * `N=1, M=100`:形状是一条线。正方形只有边长为1的,共100个。长方形(非正方形)是0个,因为所有矩形都是1×k的,也是正方形(当k=1时?不,1x2是长方形)。所以结果应该是 `100, (总共C(2,2)*C(101,2) - 100 = 1*5050 - 100 = 4950)`。 4. **代码风格**:使用了类型注解 `def count_shapes(N, M):` 和清晰的三步逻辑,提高了代码的可读性和可维护性。 希望这个解答能帮助你彻底理解这个问题!如果还有任何疑问,欢迎继续提问。 ######[AI写代码神器 | 1769点数解答 | 2026-06-05 21:50:08]
- 棋盘方格中正方形与长方形数量的计算方法(字节豆包 | 460点数解答 | 2026-04-20 12:14:43)30
- Python 实现球类:精准计算半径、表面积与体积,附输入验证与异常处理!(阿里通义 | 261点数解答 | 2024-11-28 21:19:39)407
- Python 破解:计算 n*n 网格中只含 1 的最大矩形数字和! (字节豆包 | 534点数解答 | 2026-02-07 20:24:57)42
- Pascal 实现:输出数字组成的 n*n 正方形及代码详解(字节豆包 | 443点数解答 | 2025-12-07 17:08:31)62
- C语言实现:输出第i列由数字i组成的n*n正方形及详细解析(字节豆包 | 344点数解答 | 2025-12-07 17:09:34)73
- Python:根据输入边长生成数字组成的正方形图案(字节豆包 | 216点数解答 | 2025-12-13 21:33:12)44
- Python实现生成第i列由数字i组成的n×n正方形及代码详解(字节豆包 | 230点数解答 | 2025-12-13 21:33:47)70
- Java 实现:从点类到圆类,计算圆心坐标(50,30)、半径 4 的圆周长与面积(字节豆包 | 246点数解答 | 2024-11-11 16:36:30)367
- 51 单片机:定时器 0 实现 8 个 LED 循环点亮,附代码及优化建议(字节豆包 | 1193点数解答 | 2024-12-27 15:10:29)371
- 用 JS 中 for 循环实现 1 到 100 相加并输出结果到页面的完整代码 ( | 240点数解答 | 2024-05-20 22:11:29)522
- 用 JS 的 while 循环实现 1 到 100 相加并输出到页面的代码揭秘( | 47点数解答 | 2024-05-20 22:16:48)401
- C++ 实现游戏赢家判断:巧妙找出满足和条件的最大数 (DeepSeek | 506点数解答 | 2025-06-20 16:18:09)136