Problem Summary

Two ladders of integer lengths \(x\) and \(y\) lean across a street of integer width \(w\), and they cross at integer height \(h\). We must count all triplets \((x,y,h)\) with

$$0\lt x\lt y\lt 10^6$$

that produce an integer street width \(w\).

Mathematical Approach

1) Rewrite the geometry using two right triangles

Let \(a\) and \(b\) be the wall-heights reached by the two ladders. Then each ladder forms a right triangle with common horizontal leg \(w\):

$$x^2=w^2+a^2,\qquad y^2=w^2+b^2.$$

In the classical crossing-ladders geometry, the intersection height is

$$h=\frac{ab}{a+b}.$$

So the problem becomes: find two integer right triangles sharing the same width \(w\), with integer vertical legs \(a,b\), such that \(ab/(a+b)\) is also an integer.

2) Generate all integer ladders from Pythagorean triples

Every primitive integer right triangle is generated by Euclid's formula

$$u>v\ge 1,\qquad \gcd(u,v)=1,\qquad u-v\text{ odd},$$

$$w_0=u^2-v^2,\qquad a_0=2uv,\qquad c_0=u^2+v^2,$$

up to swapping the two legs. After multiplying by a scale \(t\), we get

$$w=t\,w_0,\qquad a=t\,a_0,\qquad x=t\,c_0.$$

The implementation stores, for each width \(w\), every possible pair

$$ (a,x) $$

meaning: “there exists a ladder of integer length \(x\) crossing a street of width \(w\) and reaching height \(a\).”

3) Pair two ladders with the same width

For a fixed width \(w\), pick two stored entries \((a,x)\) and \((b,y)\) with \(a\ne b\). They describe exactly the two ladders of the problem. The crossing height is integer precisely when

$$h=\frac{ab}{a+b}\in\mathbb Z,$$

which is equivalent to the divisibility test

$$ab \bmod (a+b)=0.$$

This is the only remaining condition once the two right triangles are known.

4) Recover the official \((x,y,h)\) triplets

The code stores \((a,b,w)\) internally, but that is equivalent to the official data \((x,y,h)\), because for fixed \(w\),

$$x=\sqrt{w^2+a^2},\qquad y=\sqrt{w^2+b^2},\qquad h=\frac{ab}{a+b}.$$

All three are integers by construction plus the divisibility test above.

The sample case

$$x=70,\qquad y=119,\qquad h=30$$

comes from

$$w=56,\qquad a=42,\qquad b=105,$$

since

$$70^2=56^2+42^2,\qquad 119^2=56^2+105^2,\qquad \frac{42\cdot105}{42+105}=30.$$

The source code checkpoint solve(200)=5 matches the five sample triplets on the Project Euler page.

5) Why deduplication is still used

A width can be reached from both leg orders of a primitive triple, and scaled triples can generate the same geometric configuration in different traversal orders. The code sorts the candidates for each width and inserts canonical tuples into a set so that each ladder pair is counted once.

How the Code Works

1) Bucket by width. by_width[w] stores all pairs \((a,x)\) belonging to that street width.

2) Triple generation. The loops over \((i,j)\) generate primitive Pythagorean triples, then scale them while the hypotenuse remains below the limit.

3) Pair scan inside each width. For every width bucket, the code tests every ordered pair of distinct heights and checks whether \((ab)\bmod(a+b)=0\).

4) Canonical set insertion. Valid pairs are inserted into a set to avoid double counting.

5) Final answer. For the Project Euler bound \(10^6\), the implementation returns

$$210139.$$

Complexity Analysis

Pythagorean generation is bounded by the usual \(u^2+v^2\lt 10^6\) region, and each primitive triple is scaled until the hypotenuse limit is reached. The dominant cost is the pairwise scan inside each width bucket. In practice these buckets stay moderate enough for the method to finish comfortably, and memory is dominated by the width-indexed candidate lists plus the deduplication set.

Further Reading

  1. Problem page: https://projecteuler.net/problem=309
  2. Pythagorean triples: https://en.wikipedia.org/wiki/Pythagorean_triple
  3. Crossing ladders formula: https://en.wikipedia.org/wiki/Crossing_ladders

Problemzusammenfassung

Zwei Leitern der ganzzahligen Längen \(x\) und \(y\) stehen über einer Straße der ganzzahligen Breite \(w\) und schneiden sich in der ganzzahligen Höhe \(h\). Gesucht ist die Anzahl aller Tripel \((x,y,h)\) mit

$$0\lt x\lt y\lt 10^6,$$

für die auch \(w\) ganzzahlig ist.

Mathematischer Ansatz

1) Geometrische Umformung in zwei rechtwinklige Dreiecke

Seien \(a\) und \(b\) die Höhen an den beiden Wänden. Dann gilt

$$x^2=w^2+a^2,\qquad y^2=w^2+b^2.$$

Für die Kreuzungshöhe gilt in der klassischen Leitergeometrie

$$h=\frac{ab}{a+b}.$$

Damit reduziert sich die Aufgabe auf zwei ganzzahlige rechtwinklige Dreiecke mit gemeinsamer Breite \(w\), deren Höhen \(a,b\) zusätzlich eine ganzzahlige Harmonische-Mittel-Bedingung erfüllen.

2) Alle ganzzahligen Leitern via pythagoreische Tripel

Primitive Tripel entstehen aus

$$u>v\ge 1,\qquad \gcd(u,v)=1,\qquad u-v\text{ ungerade},$$

$$w_0=u^2-v^2,\qquad a_0=2uv,\qquad c_0=u^2+v^2,$$

bis auf Vertauschung der Katheten. Nach Skalierung mit \(t\) erhält man

$$w=t\,w_0,\qquad a=t\,a_0,\qquad x=t\,c_0.$$

Der Code speichert daher zu jeder Breite \(w\) alle möglichen Paare

$$ (a,x), $$

also „Höhe an der Wand“ plus „Leiterlänge“.

3) Zwei Leitern mit gleicher Breite koppeln

Für feste Breite \(w\) wähle zwei Einträge \((a,x)\) und \((b,y)\) mit \(a\ne b\). Dann ist die Schnittpunkthöhe genau dann ganzzahlig, wenn

$$h=\frac{ab}{a+b}\in\mathbb Z,$$

also äquivalent

$$ab \bmod (a+b)=0.$$

4) Rückkehr zu den offiziellen \((x,y,h)\)-Tripeln

Intern arbeitet der Code mit \((a,b,w)\), aber das ist äquivalent zu den gesuchten Daten, denn bei festem \(w\) gilt

$$x=\sqrt{w^2+a^2},\qquad y=\sqrt{w^2+b^2},\qquad h=\frac{ab}{a+b}.$$

Das Beispiel

$$x=70,\qquad y=119,\qquad h=30$$

entspricht

$$w=56,\qquad a=42,\qquad b=105,$$

denn

$$70^2=56^2+42^2,\qquad 119^2=56^2+105^2,\qquad \frac{42\cdot105}{42+105}=30.$$

Der Checkpoint solve(200)=5 trifft genau die fünf Beispieltripel aus der Aufgabenstellung.

5) Warum trotzdem dedupliziert wird

Dieselbe geometrische Konfiguration kann durch Kathetenvertauschung oder unterschiedliche Traversierungsreihenfolgen mehrfach auftauchen. Deshalb sortiert der Code jede Breitenklasse und legt kanonische Tupel in einer Menge ab.

Wie der Code arbeitet

1) Gruppierung nach Breite. by_width[w] sammelt alle Paare \((a,x)\) für diese Breite.

2) Tripelerzeugung. Die Schleifen über \((i,j)\) erzeugen primitive Tripel und skalieren sie, solange die Hypotenuse unter der Grenze bleibt.

3) Lokaler Paarvergleich. Innerhalb jeder Breitenklasse werden alle verschiedenen Höhenpaare geprüft und die Bedingung \((ab)\bmod(a+b)=0\) getestet.

4) Set-basierte Eindeutigkeit. Gültige Konfigurationen werden kanonisch in einer Menge gespeichert.

5) Endwert. Für die Euler-Grenze \(10^6\) gibt die Implementierung

$$210139$$

zurück.

Komplexitätsanalyse

Die Tripelerzeugung bleibt auf den Bereich \(u^2+v^2\lt 10^6\) beschränkt; jedes primitive Tripel wird nur bis zur Hypotenusengrenze skaliert. Dominant ist der paarweise Test innerhalb jeder Breitenklasse. In der Praxis bleiben diese Listen moderat genug; der Speicherbedarf wird vor allem durch die Breiten-Buckets und das Deduplikations-Set bestimmt.

Weiterführende Hinweise

  1. Problem: https://projecteuler.net/problem=309
  2. Pythagoreische Tripel: https://en.wikipedia.org/wiki/Pythagorean_triple
  3. Kreuzende Leitern: https://en.wikipedia.org/wiki/Crossing_ladders

Problem Özeti

Uzunlukları tam sayı olan iki merdiven, genişliği tam sayı olan bir sokağı çapraz geçiyor ve kesişme yüksekliği \(h\) de tam sayı oluyor. Soru,

$$0\lt x\lt y\lt 10^6$$

koşulunu sağlayan kaç \((x,y,h)\) üçlüsünün tam sayı bir sokak genişliği \(w\) ürettiğini soruyor.

Matematiksel Yaklaşım

1) Geometriyi iki dik üçgen olarak yeniden yazmak

İki merdivenin duvarda ulaştığı yükseklikleri \(a\) ve \(b\) ile gösterelim. O zaman her merdiven aynı yatay genişlik \(w\) ile bir dik üçgen oluşturur:

$$x^2=w^2+a^2,\qquad y^2=w^2+b^2.$$

Klasik crossing-ladders formülü ise

$$h=\frac{ab}{a+b}$$

şeklindedir. Böylece problem, ortak tabanı \(w\) olan iki tam kenarlı dik üçgen bulup ayrıca \(ab/(a+b)\)'nin tam sayı olmasını istemeye indirgenir.

2) Tüm tam kenarlı merdivenleri Pisagor üçlülerinden üretmek

Primitive üçlüler Euclid formülü ile gelir:

$$u>v\ge 1,\qquad \gcd(u,v)=1,\qquad u-v\text{ tek},$$

$$w_0=u^2-v^2,\qquad a_0=2uv,\qquad c_0=u^2+v^2,$$

burada iki dik kenarın yeri gerekirse değiştirilebilir. Ölçek \(t\) ile

$$w=t\,w_0,\qquad a=t\,a_0,\qquad x=t\,c_0$$

elde edilir. Kod, her genişlik \(w\) için tüm

$$ (a,x) $$

çiftlerini saklar; yani “bu genişlikte, duvar yüksekliği \(a\) ve merdiven uzunluğu \(x\) mümkündür” bilgisini tutar.

3) Aynı genişlikte iki merdiveni eşleştirmek

Sabit bir \(w\) için iki giriş \((a,x)\) ve \((b,y)\) seçilir. Bunlar problemdeki iki merdiveni temsil eder. Kesişim yüksekliğinin tam sayı olması tam ve ancak şu koşulda gerçekleşir:

$$h=\frac{ab}{a+b}\in\mathbb Z \iff ab \bmod (a+b)=0.$$

Dolayısıyla ortak genişlikli iki dik üçgen üretildikten sonra kontrol edilmesi gereken tek ek koşul budur.

4) Resmî \((x,y,h)\) üçlülerine geri dönmek

Kod içeride \((a,b,w)\) ile çalışsa da bu, resmî problem değişkenleriyle birebir eşdeğerdir; çünkü sabit \(w\) için

$$x=\sqrt{w^2+a^2},\qquad y=\sqrt{w^2+b^2},\qquad h=\frac{ab}{a+b}$$

tam olarak belirlenir.

Örnek olarak problemdeki

$$x=70,\qquad y=119,\qquad h=30$$

üçlüsü aslında

$$w=56,\qquad a=42,\qquad b=105$$

verilerinden gelir; gerçekten

$$70^2=56^2+42^2,\qquad 119^2=56^2+105^2,\qquad \frac{42\cdot105}{42+105}=30.$$

Koddaki solve(200)=5 kontrolü, resmî sayfadaki beş örnek üçlüyle tam uyumludur.

5) Neden yine de tekilleştirme yapılıyor?

Aynı geometrik durum, primitive üçlünün iki dik kenarının yer değiştirmesinden veya farklı dolaşım sıralarından birden çok kez üretilebilir. Bu yüzden kod her genişlik listesini sıralar ve geçerli adayları kanonik tuple olarak bir sete ekler.

Kodun Çalışma Mantığı

1) Genişliğe göre bucket. by_width[w], bu genişlik için mümkün tüm \((a,x)\) çiftlerini tutar.

2) Üçlü üretimi. \((i,j)\) döngüleri primitive Pisagor üçlülerini üretir; sonra hipotenüs sınırı aşılana kadar ölçeklenir.

3) Yerel ikili tarama. Her genişlik listesinde farklı yükseklik çiftleri denenir ve \((ab)\bmod(a+b)=0\) şartı kontrol edilir.

4) Set ile tekilleştirme. Geçerli konfigürasyonlar canonical biçimde sete eklenerek tekrar sayım önlenir.

5) Nihai değer. Euler sınırı \(10^6\) için çözüm

$$210139$$

olarak döner.

Karmaşıklık Analizi

Üçlü üretimi, \(u^2+v^2\lt 10^6\) bölgesiyle sınırlıdır ve her primitive üçlü hipotenüs sınırına kadar ölçeklenir. Baskın maliyet, her genişlik bucket'ındaki ikili taramadır. Pratikte bu bucket boyutları yeterince küçük kaldığından yöntem rahatça çalışır; bellek maliyeti esas olarak genişliğe göre saklanan listeler ve tekilleştirme setidir.

İleri Okuma

  1. Problem metni: https://projecteuler.net/problem=309
  2. Pisagor üçlüleri: https://en.wikipedia.org/wiki/Pythagorean_triple
  3. Crossing ladders formülü: https://en.wikipedia.org/wiki/Crossing_ladders

Resumen del Problema

Dos escaleras de longitudes enteras \(x\) e \(y\) cruzan una calle de anchura entera \(w\), y su punto de cruce tiene altura entera \(h\). Hay que contar todos los tripletes \((x,y,h)\) con

$$0\lt x\lt y\lt 10^6$$

que producen una anchura \(w\) también entera.

Enfoque Matemático

1) Reescribir la geometría como dos triángulos rectángulos

Sean \(a\) y \(b\) las alturas alcanzadas en las paredes. Entonces

$$x^2=w^2+a^2,\qquad y^2=w^2+b^2.$$

La fórmula clásica de escaleras cruzadas da

$$h=\frac{ab}{a+b}.$$

Así, el problema se reduce a encontrar dos triángulos rectángulos enteros con la misma base \(w\) y con \(ab/(a+b)\) entero.

2) Generar todas las escaleras enteras mediante ternas pitagóricas

Las ternas primitivas se obtienen de

$$u>v\ge 1,\qquad \gcd(u,v)=1,\qquad u-v\text{ impar},$$

$$w_0=u^2-v^2,\qquad a_0=2uv,\qquad c_0=u^2+v^2,$$

salvo intercambio de catetos. Al escalar por \(t\):

$$w=t\,w_0,\qquad a=t\,a_0,\qquad x=t\,c_0.$$

El programa guarda, para cada anchura \(w\), todos los pares

$$ (a,x) $$

posibles.

3) Emparejar dos escaleras de la misma anchura

Fijada una anchura \(w\), elegimos dos entradas \((a,x)\) y \((b,y)\). La altura de cruce es entera exactamente cuando

$$h=\frac{ab}{a+b}\in\mathbb Z \iff ab \bmod (a+b)=0.$$

4) Recuperar los tripletes oficiales \((x,y,h)\)

Aunque internamente el código trabaja con \((a,b,w)\), eso es equivalente a los datos del problema porque

$$x=\sqrt{w^2+a^2},\qquad y=\sqrt{w^2+b^2},\qquad h=\frac{ab}{a+b}.$$

El ejemplo oficial

$$x=70,\qquad y=119,\qquad h=30$$

corresponde a

$$w=56,\qquad a=42,\qquad b=105,$$

ya que

$$70^2=56^2+42^2,\qquad 119^2=56^2+105^2,\qquad \frac{42\cdot105}{42+105}=30.$$

El checkpoint solve(200)=5 coincide con los cinco ejemplos oficiales.

5) Por qué se necesita deduplicación

La misma configuración geométrica puede aparecer varias veces por intercambio de catetos o por distintos recorridos de generación. Por eso el código ordena cada cubeta de anchura y guarda solo tuplas canónicas en un conjunto.

Cómo Funciona el Código

1) Agrupación por anchura. by_width[w] contiene todos los pares \((a,x)\) para esa anchura.

2) Generación de ternas. Los bucles sobre \((i,j)\) producen ternas pitagóricas primitivas y luego sus escalados mientras la hipotenusa siga bajo el límite.

3) Barrido por pares dentro de cada anchura. Se prueban todas las parejas de alturas distintas y se verifica \((ab)\bmod(a+b)=0\).

4) Inserción canónica. Las soluciones válidas se insertan en un conjunto para no contar repeticiones.

5) Resultado final. Para el límite de Project Euler, la implementación devuelve

$$210139.$$

Complejidad

La generación pitagórica vive en la región \(u^2+v^2\lt 10^6\), y cada terna primitiva se escala hasta el límite de hipotenusa. El coste dominante es el barrido cuadrático dentro de cada lista local por anchura. En la práctica esas listas siguen siendo manejables; la memoria la dominan las listas por anchura y el conjunto de deduplicación.

Lecturas

  1. Problema: https://projecteuler.net/problem=309
  2. Ternas pitagóricas: https://en.wikipedia.org/wiki/Pythagorean_triple
  3. Escaleras cruzadas: https://en.wikipedia.org/wiki/Crossing_ladders

问题概述

两把长度为整数的梯子,跨过一条宽度为整数的街道,交点高度 \(h\) 也要求是整数。题目要统计所有满足

$$0\lt x\lt y\lt 10^6$$

并且能得到整数街宽 \(w\) 的三元组 \((x,y,h)\) 的个数。

数学方法

1) 把几何改写成两个直角三角形

设两把梯子在墙上达到的高度分别为 \(a\) 和 \(b\)。那么有

$$x^2=w^2+a^2,\qquad y^2=w^2+b^2.$$

经典交叉梯子公式给出

$$h=\frac{ab}{a+b}.$$

因此问题就变成:找到两组共用同一底边 \(w\) 的整数直角三角形,并且 \(ab/(a+b)\) 还是整数。

2) 用毕达哥拉斯三元组生成所有整数梯子

原始三元组来自

$$u>v\ge 1,\qquad \gcd(u,v)=1,\qquad u-v\text{ 为奇数},$$

$$w_0=u^2-v^2,\qquad a_0=2uv,\qquad c_0=u^2+v^2,$$

其中两条直角边可以交换。乘上比例因子 \(t\) 后得到

$$w=t\,w_0,\qquad a=t\,a_0,\qquad x=t\,c_0.$$

程序因此对每个宽度 \(w\) 存储所有可能的

$$ (a,x) $$

对,也就是“墙高 + 梯长”。

3) 在同一宽度下配对两把梯子

固定宽度 \(w\) 后,选两项 \((a,x)\) 与 \((b,y)\)。交点高度为整数当且仅当

$$h=\frac{ab}{a+b}\in\mathbb Z \iff ab \bmod (a+b)=0.$$

4) 回到题目要求的 \((x,y,h)\)

虽然代码内部使用的是 \((a,b,w)\),但它与题目中的三元组完全等价,因为

$$x=\sqrt{w^2+a^2},\qquad y=\sqrt{w^2+b^2},\qquad h=\frac{ab}{a+b}.$$

例如官方样例

$$x=70,\qquad y=119,\qquad h=30$$

对应

$$w=56,\qquad a=42,\qquad b=105,$$

因为

$$70^2=56^2+42^2,\qquad 119^2=56^2+105^2,\qquad \frac{42\cdot105}{42+105}=30.$$

源码中的检查点 solve(200)=5 正好对应题面给出的 5 个样例。

5) 为什么还需要去重

同一个几何配置可能因为直角边交换或不同生成顺序而被重复遇到。因此程序对每个宽度桶排序,并把规范化后的元组放入集合,只计数一次。

代码如何工作

1) 按宽度分桶。 by_width[w] 存储该宽度下所有可能的 \((a,x)\) 对。

2) 生成三元组。 \((i,j)\) 双循环产生原始毕达哥拉斯三元组,再按比例放大直到斜边超过上限。

3) 桶内两两扫描。 对每个宽度桶中的不同高度对,检查 \((ab)\bmod(a+b)=0\)。

4) 集合去重。 有效配置以规范形式插入集合,避免重复计数。

5) 最终结果。 对 Project Euler 的上界,程序返回

$$210139.$$

复杂度分析

三元组生成受区域 \(u^2+v^2\lt 10^6\) 约束,每个原始三元组都会被放大到斜边上限。主要成本来自每个宽度桶内部的成对扫描。实践中这些局部列表并不大,因此算法可行;空间主要由按宽度保存的候选列表和去重集合占据。

延伸阅读

  1. 题目页面: https://projecteuler.net/problem=309
  2. 毕达哥拉斯三元组: https://en.wikipedia.org/wiki/Pythagorean_triple
  3. 交叉梯子公式: https://en.wikipedia.org/wiki/Crossing_ladders

Краткое описание

Две лестницы целых длин \(x\) и \(y\) пересекают улицу целой ширины \(w\), и высота пересечения \(h\) тоже целая. Требуется посчитать число троек \((x,y,h)\), удовлетворяющих

$$0\lt x\lt y\lt 10^6,$$

для которых ширина \(w\) тоже получается целой.

Математический подход

1) Перепишем геометрию как два прямоугольных треугольника

Пусть \(a\) и \(b\) — высоты, на которые лестницы поднимаются по стенам. Тогда

$$x^2=w^2+a^2,\qquad y^2=w^2+b^2.$$

Высота пересечения в задаче о перекрещивающихся лестницах равна

$$h=\frac{ab}{a+b}.$$

Значит, нужно найти две целочисленные прямоугольные тройки с общей шириной \(w\), причем \(ab/(a+b)\) должно быть целым.

2) Генерация всех целочисленных лестниц через пифагоровы тройки

Примитивные тройки задаются формулой

$$u>v\ge 1,\qquad \gcd(u,v)=1,\qquad u-v\text{ нечетно},$$

$$w_0=u^2-v^2,\qquad a_0=2uv,\qquad c_0=u^2+v^2,$$

с точностью до перестановки катетов. После масштабирования на \(t\):

$$w=t\,w_0,\qquad a=t\,a_0,\qquad x=t\,c_0.$$

Поэтому программа хранит для каждой ширины \(w\) все возможные пары

$$ (a,x). $$

3) Сопряжение двух лестниц одинаковой ширины

Для фиксированной ширины \(w\) выбираются две записи \((a,x)\) и \((b,y)\). Высота пересечения целая тогда и только тогда, когда

$$h=\frac{ab}{a+b}\in\mathbb Z \iff ab \bmod (a+b)=0.$$

4) Возврат к официальным тройкам \((x,y,h)\)

Хотя внутри код работает с \((a,b,w)\), это полностью эквивалентно данным задачи, потому что

$$x=\sqrt{w^2+a^2},\qquad y=\sqrt{w^2+b^2},\qquad h=\frac{ab}{a+b}.$$

Например, официальный пример

$$x=70,\qquad y=119,\qquad h=30$$

соответствует

$$w=56,\qquad a=42,\qquad b=105,$$

поскольку

$$70^2=56^2+42^2,\qquad 119^2=56^2+105^2,\qquad \frac{42\cdot105}{42+105}=30.$$

Контроль solve(200)=5 совпадает с пятью примерами из условия.

5) Зачем нужна дедупликация

Одна и та же геометрическая конфигурация может появиться несколько раз из-за перестановки катетов или разных порядков обхода. Поэтому код сортирует каждый список ширины и складывает канонические кортежи в множество.

Как работает код

1) Группировка по ширине. by_width[w] хранит все пары \((a,x)\) для данной ширины.

2) Генерация троек. Циклы по \((i,j)\) порождают примитивные тройки и их масштабы, пока гипотенуза не превысит лимит.

3) Попарный просмотр внутри ширины. Для каждой ширины проверяются все пары разных высот и тестируется условие \((ab)\bmod(a+b)=0\).

4) Каноническое множество. Валидные конфигурации кладутся в set, чтобы не было повторного счета.

5) Финальное значение. Для предела Project Euler решение возвращает

$$210139.$$

Сложность

Генерация троек ограничена областью \(u^2+v^2\lt 10^6\), а каждая примитивная тройка масштабируется до предела гипотенузы. Основная стоимость — попарный перебор внутри каждого списка ширины. На практике эти списки остаются достаточно небольшими; память определяется списками по ширинам и множеством для дедупликации.

Дополнительные материалы

  1. Условие: https://projecteuler.net/problem=309
  2. Пифагоровы тройки: https://en.wikipedia.org/wiki/Pythagorean_triple
  3. Формула пересекающихся лестниц: https://en.wikipedia.org/wiki/Crossing_ladders

ملخص المسألة

لدينا سلّمان بطولين صحيحين \(x\) و\(y\)، يعبران شارعًا عرضه الصحيح \(w\)، كما أن ارتفاع نقطة التقاطع \(h\) عدد صحيح أيضًا. المطلوب عدّ جميع الثلاثيات \((x,y,h)\) التي تحقق

$$0\lt x\lt y\lt 10^6$$

وتنتج عرض شارع صحيحًا \(w\).

المنهج الرياضي

1) إعادة كتابة الهندسة على شكل مثلثين قائمين

لتكن \(a\) و\(b\) هما الارتفاعان اللذان يصل إليهما السلّمان على الجدارين. عندئذ

$$x^2=w^2+a^2,\qquad y^2=w^2+b^2.$$

أما ارتفاع نقطة التقاطع في مسألة السلالم المتقاطعة الكلاسيكية فهو

$$h=\frac{ab}{a+b}.$$

إذًا تصبح المسألة: إيجاد مثلثين قائمين صحيحين يشتركان في القاعدة \(w\)، مع شرط إضافي هو أن \(ab/(a+b)\) عدد صحيح.

2) توليد جميع السلالم الصحيحة من ثلاثيات فيثاغورس

تُعطى الثلاثيات الأولية بواسطة

$$u>v\ge 1,\qquad \gcd(u,v)=1,\qquad u-v\text{ فردي},$$

$$w_0=u^2-v^2,\qquad a_0=2uv,\qquad c_0=u^2+v^2,$$

مع السماح بتبديل الضلعين القائمين. وبعد التكبير بعامل \(t\) نحصل على

$$w=t\,w_0,\qquad a=t\,a_0,\qquad x=t\,c_0.$$

لذلك يخزّن الكود لكل عرض \(w\) جميع الأزواج الممكنة

$$ (a,x). $$

3) إقران سلّمين لهما العرض نفسه

بعد تثبيت العرض \(w\)، نختار زوجين \((a,x)\) و\((b,y)\). يكون ارتفاع التقاطع صحيحًا تمامًا عندما

$$h=\frac{ab}{a+b}\in\mathbb Z \iff ab \bmod (a+b)=0.$$

4) العودة إلى الثلاثيات الرسمية \((x,y,h)\)

رغم أن الكود يعمل داخليًا مع \((a,b,w)\)، فهذا مكافئ تمامًا لمعطيات المسألة، لأن

$$x=\sqrt{w^2+a^2},\qquad y=\sqrt{w^2+b^2},\qquad h=\frac{ab}{a+b}.$$

فمثلًا المثال الرسمي

$$x=70,\qquad y=119,\qquad h=30$$

ينشأ من

$$w=56,\qquad a=42,\qquad b=105,$$

لأن

$$70^2=56^2+42^2,\qquad 119^2=56^2+105^2,\qquad \frac{42\cdot105}{42+105}=30.$$

وقيمة التحقق solve(200)=5 تطابق تمامًا الأمثلة الخمسة المذكورة في صفحة Project Euler.

5) لماذا نحتاج إلى إزالة التكرار؟

قد تظهر البنية الهندسية نفسها أكثر من مرة بسبب تبديل الضلعين القائمين أو اختلاف ترتيب التوليد. لذلك يرتّب الكود كل قائمة خاصة بعرض معين ثم يضع التمثيل القياسي داخل مجموعة حتى لا تُحسب الحالة إلا مرة واحدة.

كيف يعمل الكود

1) تجميع حسب العرض. المصفوفة by_width[w] تحفظ جميع الأزواج \((a,x)\) الممكنة لذلك العرض.

2) توليد الثلاثيات. الحلقات على \((i,j)\) تولّد ثلاثيات فيثاغورس الأولية ثم تكبّرها ما دامت الوتر تحت الحد.

3) الفحص الزوجي داخل كل عرض. لكل عرض، تُفحَص جميع أزواج الارتفاعات المختلفة ويُختبَر الشرط \((ab)\bmod(a+b)=0\).

4) إدخال قياسي في مجموعة. تُحفظ الحلول الصحيحة بشكل قياسي داخل مجموعة من أجل منع العد المكرر.

5) النتيجة النهائية. عند حد Project Euler تُرجِع الخوارزمية القيمة

$$210139.$$

تحليل التعقيد

توليد الثلاثيات محصور في المنطقة \(u^2+v^2\lt 10^6\)، وكل ثلاثية أولية تُكبَّر حتى حد الوتر. الكلفة الغالبة تأتي من الفحص الثنائي داخل كل سلة عرض. عمليًا تبقى هذه القوائم محلية الحجم، ولذلك تنجح الطريقة بسهولة؛ والذاكرة تهيمن عليها قوائم العرض وبنية إزالة التكرار.

مراجع إضافية

  1. صفحة المسألة: https://projecteuler.net/problem=309
  2. ثلاثيات فيثاغورس: https://en.wikipedia.org/wiki/Pythagorean_triple
  3. صيغة السلالم المتقاطعة: https://en.wikipedia.org/wiki/Crossing_ladders