新增 0039、0040 题解及配套文档

This commit is contained in:
2026-01-10 22:40:00 +08:00
parent d288475bf9
commit 9c91d0f0d6
3 changed files with 291 additions and 0 deletions

View File

@@ -0,0 +1,105 @@
# 勾股三元组
以下为AI总结。
---
### 1. 核心定义
**勾股三元组** 是指三个**正整数** \((a, b, c)\),满足**勾股定理**方程:
\[
a^2 + b^2 = c^2
\]
其中 \(c\) 称为**斜边**\(a\) 和 \(b\) 称为**直角边**。
**例如**\((3, 4, 5)\),因为 \(3^2 + 4^2 = 9 + 16 = 25 = 5^2\)。
---
### 2. 关键分类:本原 vs 非本原
#### **本原勾股三元组**
- **定义**:满足 \(\gcd(a, b, c) = 1\) 的勾股三元组。即三个数互质最大公约数为1
- **性质**
1. \(a\) 和 \(b\) 必然**一奇一偶**。
2. \(c\) 永远是奇数。
3. 任意两个数互质。
- **例子**\((3, 4, 5)\) \((5, 12, 13)\) \((8, 15, 17)\)。
- **重要性**:所有勾股三元组的“基本生成元”,非本原三元组都是本原三元组的正整数倍缩放。
#### **非本原(导出)勾股三元组**
- **定义**由一个本原三元组乘以一个大于1的正整数 \(k\) 得到,即 \((ka, kb, kc)\),此时 \(\gcd(a, b, c) > 1\)。
- **例子**\((6, 8, 10)\) 是 \((3, 4, 5)\) 的2倍。
---
### 3. 核心生成公式(欧几里得公式)
这是一个在数论中用于**生成所有本原勾股三元组**的经典公式。
给定任意一对**互质**的正整数 \(m\) 和 \(n\) \(m > n > 0\)),且满足:
- \(m\) 和 \(n\) **一奇一偶**(即不同时为奇数,也不同时为偶数)。
则可生成一个本原勾股三元组:
\[
\begin{align*}
a &= m^2 - n^2 \\
b &= 2mn \\
c &= m^2 + n^2
\end{align*}
\]
**推导思路**
从方程 \(a^2 + b^2 = c^2\) 出发,进行代数变形。一种常见方法是将方程重写为:
\[
c^2 - a^2 = b^2 \quad \Rightarrow \quad (c-a)(c+a) = b^2
\]
通过设定 \(\frac{c+a}{b} = \frac{m}{n}\)(既约分数),并引入参数 \(m, n\),经过整理即可得到上述公式。它本质上是利用了复数模的性质:\(|m + ni|^2 = m^2 + n^2\)。
**例子**:取 \(m=2, n=1\)(互质,一奇一偶)
\[
a = 4-1=3, \quad b = 2\times2\times1=4, \quad c = 4+1=5 \quad \Rightarrow (3,4,5)
\]
取 \(m=3, n=2\)
\[
a=9-4=5, \quad b=12, \quad c=9+4=13 \quad \Rightarrow (5,12,13)
\]
**重要结论****所有本原勾股三元组都可以由唯一一对满足条件的 \((m, n)\) 通过此公式生成**。所有勾股三元组(包括非本原)则是本原三元组的正整数倍。
---
### 4. 几何视角与三角学联系
在单位圆 \(x^2 + y^2 = 1\) 上,有理点 \(\left( \frac{a}{c}, \frac{b}{c} \right)\) 对应于一个勾股三元组 \((a, b, c)\)。
通过参数化 \(t = \tan(\theta/2)\)**半角正切公式**),令 \(t = \frac{n}{m}\)(有理数),则:
\[
\cos\theta = \frac{1-t^2}{1+t^2} = \frac{m^2-n^2}{m^2+n^2} = \frac{a}{c}, \quad \sin\theta = \frac{2t}{1+t^2} = \frac{2mn}{m^2+n^2} = \frac{b}{c}
\]
这直接给出了欧几里得公式的三角解释。因此,寻找勾股三元组等价于寻找单位圆上的有理点。
---
### 5. 一些有趣的数学性质
1. **面积**:本原三元组生成的直角三角形的面积 \(S = \frac{1}{2}ab = mn(m-n)(m+n)\),它总是**整数**并且是6的倍数。
2. **周长**:本原三元组的周长 \(P = a+b+c = 2m(m+n)\)。
3. **斜边性质**
- 本原三元组的斜边 \(c\) 是奇数,且可以表示为两个平方数之和 \(c = m^2 + n^2\)。
- 斜边 \(c\) 的**每个**形如 \(4k+1\)\(k\)为正整数)的质因数,都对应着一种将该斜边表示为两个平方数之和的方式,从而关联到更深刻的**费马平方和定理**。
4. **无限性**:存在无限多个本原勾股三元组。
---
### 6. 历史与意义
- 最早的记录可追溯到公元前1800年左右的**古巴比伦**泥板如普林顿322号其上刻有大量勾股三元组表明古人已掌握其计算规律。
- 在古希腊,**毕达哥拉斯学派**对其进行了系统研究,并将其与几何和“完美数”观念联系。
- 在近代数学中,对勾股三元组的研究自然导向了**费马大定理**(方程 \(a^n + b^n = c^n\) 在 \(n>2\) 时无正整数解),这是数论中的一个里程碑。
- 在现代,勾股三元组出现在密码学、算法设计和一些物理问题中。
---
### 总结
勾股三元组是满足 \(a^2 + b^2 = c^2\) 的正整数三元组。其核心是**本原三元组**,可通过**欧几里得公式** \((m^2-n^2, 2mn, m^2+n^2)\) 用一对互质且一奇一偶的参数 \((m, n)\) **完全生成**。它在数学上连接了几何(直角三角形)、数论(平方和、质因数分解)和代数(曲线有理点),是一个基础而内涵丰富的概念。

View File

@@ -6,3 +6,98 @@ If p is the perimeter of a right angle triangle with integral length sides,
For which value of p<=1000, is the number of solutions maximised?
"""
import time
import math
def timer(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"{func.__name__} took time: {end_time - start_time:.6f} seconds")
return result
return wrapper
def generate_pythagorean_triples(max_perimeter: int = 1000) :
"""
使用yield生成勾股三元组的m和n参数
参数:
max_perimeter: 三角形周长的最大值
生成:
(m, n) 元组,满足:
- m > n > 0
- m和n互质 (gcd(m, n) == 1)
- m和n一奇一偶
- 三角形周长 2*m*(m+n) < max_perimeter
"""
# 从m=2开始因为m>n≥1
m = 2
while True:
# 对于每个mn从1到m-1
for n in range(1, m):
# 检查是否满足互质条件
if math.gcd(m, n) != 1:
continue
# 检查是否一奇一偶
if (m % 2) == (n % 2):
continue
# 计算对应三角形的周长
perimeter = 2 * m * (m + n)
# 如果周长超过限制,则停止生成
if perimeter >= max_perimeter:
# 对于当前m如果最小周长当n=1时已经超过限制
# 那么后续更大的m也会超过所以完全停止
if n == 1:
return
# 如果周长在限制内则yield当前(m, n)
if perimeter < max_perimeter:
yield (m, n)
m += 1
def triangle_length(m:int, n:int) -> int:
return 2 * m * (m + n)
def get_abc(m:int, n:int) -> tuple[int, int, int]:
a = m**2 - n**2
b = 2 * m * n
c = m**2 + n**2
return a, b, c
def primitive_triangles(limit: int = 1000) -> dict[int, list] :
triangle_lengths = {}
for m, n in generate_pythagorean_triples(limit):
length = triangle_length(m, n)
if length not in triangle_lengths:
triangle_lengths[length] = set()
a,b,c = get_abc(m, n)
triangle_lengths[length].add((a, b, c))
for k in range(2, limit // length + 1) :
lenp = k * (a + b + c)
if lenp not in triangle_lengths:
triangle_lengths[lenp] = set()
triangle_lengths[lenp].add((a*k, b*k, c*k))
return triangle_lengths
@timer
def main():
max_perimeter = 1000
triangle_lengths = primitive_triangles(max_perimeter)
print(triangle_lengths)
max_length = max(triangle_lengths, key=lambda x: len(triangle_lengths[x]))
print(f"Max length: {max_length}, Count: {len(triangle_lengths[max_length])}")
if __name__ == "__main__":
main()