问题
毕达哥拉斯三元组由三个自然数 a < b < c 组成,并满足 a2+b2=c2, 例如 32+42=52
有且只有一个毕达哥拉斯三元组满足 a + b + c = 1000。求这个三元组的乘积 a∗b∗c
暴力枚举
为了使题目更具一般性,假设 a + b + c = n,由 a < b < c,可以得知 a<n3,max(a,n4)<b<n2
fun main() {
println("${pythagoreanTriplet(12)}") // 3 * 4 * 5 = 60
println("${pythagoreanTriplet(1000)}") // 200 * 375 * 425 = 31875000
}
fun pythagoreanTriplet(n: Int): Triple<Int, Int, Int> {
if (n.and(1) == 1) {
// n 为奇数,不存在毕达哥拉斯三元组(尾数奇偶性可反证)
return Triple(0, 0, 0)
}
val upper = n.div(3)
(0 until upper).forEach { a ->
val lower = a.coerceAtLeast(n.div(4)) + 1
(lower until n.shr(1)).forEach { b ->
if (a * a + b * b == (n - a - b) * (n - a - b)) {
return Triple(a, b, n - a - b)
}
}
}
return Triple(0, 0, 0)
}
奇技淫巧
对于 0 < p < q,以下三个数可以构成毕达哥拉斯三元组: q2−p2,2∗q∗p,q2+p2
令这三个数为 a、b、c(倘若 2∗q∗p>q2−p2,调换 a、b 即可,不影响结论),则有: a+b+c=q2−p2+2∗q∗p+q2+p2=2∗q∗(q+p)=n,即:
q∗(q+p)=n2可以推出 q=√n2−q∗p<√n2;
同时可推出,p=n2q−q,又因 p < q, 故 n2q−q<q,
即 q>√n2。所以:
n = 1000 时满足区间 [√n2,√n2] 即 [√250,√500] 的整数只有 16、17、18、19、20、21、22,遍历区间,显然只有 20 是 n2=500 的因子,所以 q = 20,p = 5,故有: q2−p2=202−52=375,2∗q∗p=2∗20∗5=200,q2+p2=202+52=425
按大小顺序分别赋值 a=200,b=375,c=425,可验证: a2+b2=2002+3752=4252=c2
抠腚如下:
fun main() {
println("${pythagoreanTriplet(12)}") // 3 * 4 * 5 = 60
println("${pythagoreanTriplet(1000)}") // 200 * 375 * 425 = 31875000
}
fun pythagoreanTriplet(n: Int): Triple<Int, Int, Int> {
if (n.and(1) == 1) {
// n 为奇数,不存在毕达哥拉斯三元组(尾数奇偶性可反证)
return Triple(0, 0, 0)
}
val lower = floor(sqrt(n.toDouble()).div(2)).toInt()
val upper = ceil(sqrt(n.toDouble().div(2))).toInt()
(lower..upper).forEach { q ->
if (n.shr(1).mod(q) == 0) {
val p = n.shr(1).div(q) - q
if (p < q) {
return Triple(q * q - p * p, 2 * p * q, q * q + p * p)
}
}
}
return Triple(0, 0, 0)
}
欧几里得范数
to be continue…