Problem Summary

Let

$$T_n=\left\{(a,b,c)\in \mathbb{Z}_{>0}^3:1\le a\le b\le c,\ c\le a+b-1,\ a+b\le n\right\}.$$

For each integer triangle in \(T_n\), place the incircle first. Then, in every corner, continue packing circles that are tangent to the two sides of that angle and to the previous circle in the same corner. The quantity being averaged is the total area of the incircle together with the two largest additional circles that appear after this first placement.

If we write that triangle contribution as \(F(a,b,c)\), then the implementations compute

$$S(n)=\frac{1}{|T_n|}\sum_{(a,b,c)\in T_n} F(a,b,c).$$

The numerical checkpoints used by the implementations are

$$S(2)=0.31998,\qquad S(5)=1.25899.$$

Mathematical Approach

Fix one triangle with side lengths \(a\le b\le c\), and let \(A\le B\le C\) be the opposite angles. The geometry simplifies because the side ordering already tells us which corners can contain the largest packed circles.

Step 1: Describe the admissible triangles and angle order

The inequalities

$$1\le a\le b\le c,\qquad c\le a+b-1,\qquad a+b\le n$$

say that we average over all nondegenerate integer triangles in sorted side order. Since larger sides face larger angles, the ordering of the angles is

$$A\le B\le C.$$

This matters because a narrower corner produces a larger next tangent circle. So once the sides are sorted, the smallest angle \(A\) is the first place to look for the biggest circle after the incircle.

Step 2: Compute the incircle radius from the side lengths

Set

$$p=a+b+c,\qquad s=\frac{p}{2},\qquad x=p-2a,\qquad y=p-2b,\qquad z=p-2c.$$

Then \(x=2(s-a)\), \(y=2(s-b)\), and \(z=2(s-c)\). If \(\Delta\) is the triangle area, Heron's formula gives

$$\Delta^2=s(s-a)(s-b)(s-c).$$

The inradius is \(r=\Delta/s\), so

$$r^2=\frac{\Delta^2}{s^2}=\frac{(s-a)(s-b)(s-c)}{s}=\frac{xyz}{4p}.$$

This is exactly the compact formula used by the implementations. It avoids computing the area explicitly before the final multiplication by \(\pi\).

Step 3: Derive the geometric ratio inside one corner

Consider one angle \(\theta\). Any circle tangent to both sides of that angle has its center on the angle bisector. If the radius is \(\rho\), then the center is at distance

$$d=\frac{\rho}{\sin(\theta/2)}$$

from the vertex.

Now take two consecutive circles in the same corner, with radii \(R\) and \(R'\), both tangent to the sides and tangent to each other. Their centers lie on the same bisector, and external tangency gives

$$\frac{R-R'}{\sin(\theta/2)}=R+R'.$$

Solving for the ratio yields

$$\frac{R'}{R}=\frac{1-\sin(\theta/2)}{1+\sin(\theta/2)}=:q(\theta).$$

So each corner generates a geometric chain of radii

$$r,\ rq(\theta),\ rq(\theta)^2,\ rq(\theta)^3,\dots$$

starting from the incircle. For the two angles that actually matter in the final comparison, the half-angle identities are

$$\sin^2\left(\frac{A}{2}\right)=\frac{(s-b)(s-c)}{bc}=\frac{yz}{4bc},$$

$$\sin^2\left(\frac{B}{2}\right)=\frac{(s-a)(s-c)}{ac}=\frac{xz}{4ac}.$$

Step 4: Identify the two largest extra circles

The function \(q(\theta)\) decreases as \(\theta\) increases on \((0,\pi)\). Because \(A\le B\le C\), we have

$$q_A\ge q_B\ge q_C,$$

where \(q_A=q(A)\), \(q_B=q(B)\), and \(q_C=q(C)\).

Therefore the largest circle after the incircle is always the first corner-circle in angle \(A\), with radius \(rq_A\).

For the third selected circle, only two candidates can survive:

$$rq_B,\qquad rq_A^2.$$

The first circle in angle \(C\) is no larger than the first circle in angle \(B\), and every later circle in any corner is no larger than the first unused circle in that same corner. So the third radius is

$$r\max\{q_B,q_A^2\}.$$

Squaring the radii to convert them into area factors, the two extra contributions are

$$q_A^2,\qquad \max\{q_B^2,q_A^4\}.$$

Step 5: Final contribution of one triangle

The incircle area is \(\pi r^2\). Adding the two largest extra circles gives

$$F(a,b,c)=\pi r^2\left(1+q_A^2+\max\{q_B^2,q_A^4\}\right).$$

This is the exact formula accumulated by the implementations for every admissible triangle.

Worked Example: The equilateral triangle \((1,1,1)\)

For \(a=b=c=1\), we have

$$p=3,\qquad s=\frac{3}{2},\qquad x=y=z=1.$$

Hence

$$r^2=\frac{xyz}{4p}=\frac{1}{12}.$$

All angles equal \(\pi/3\), so

$$\sin\left(\frac{A}{2}\right)=\sin\left(\frac{\pi}{6}\right)=\frac{1}{2},\qquad q_A=q_B=\frac{1-\frac12}{1+\frac12}=\frac13.$$

Therefore

$$F(1,1,1)=\pi\cdot\frac{1}{12}\left(1+\frac{1}{9}+\max\left\{\frac{1}{9},\frac{1}{81}\right\}\right)=\pi\cdot\frac{1}{12}\left(1+\frac{1}{9}+\frac{1}{9}\right)=\frac{11\pi}{108}.$$

Numerically,

$$\frac{11\pi}{108}\approx 0.31998.$$

Since \(T_2\) contains only this one triangle, we get \(S(2)=0.31998\), matching the checkpoint.

How the Code Works

The C++, Python, and Java implementations all evaluate the same formula. They enumerate the admissible triangles in sorted order by looping over \(a\), then \(b\), then every feasible \(c\) with

$$b\le c\le a+b-1.$$

For each triangle, the implementation computes \(p\), \(x\), \(y\), and \(z\), obtains \(r^2=xyz/(4p)\), then evaluates the half-angle terms needed for \(A\) and \(B\). From those values it builds \(q_A\) and \(q_B\), forms

$$\pi r^2\left(1+q_A^2+\max\{q_B^2,q_A^4\}\right),$$

adds that quantity to a running total, and increments the triangle counter.

The final answer is the total divided by the number of triangles. The Java implementation uses compensated accumulation to reduce floating-point loss, while the C++ computation uses extended precision. The Python implementation delegates to the same compiled numerical routine, so all three implementations share the same geometry and the same checkpoints.

Complexity Analysis

The number of admissible triangles is

$$|T_n|=\sum_{a=1}^{\lfloor n/2\rfloor}\sum_{b=a}^{n-a} a,$$

because for fixed \(a\) and \(b\), the value of \(c\) runs from \(b\) to \(a+b-1\), which gives exactly \(a\) possibilities. This count is \(\Theta(n^3)\), so the overall runtime is \(\Theta(n^3)\).

The work done for each triangle is constant-time arithmetic with a few square roots and one maximum comparison. Memory usage is \(O(1)\), since the implementations only maintain a running total, a counter, and a small number of temporary floating-point values.

Footnotes and References

  1. Problem page: https://projecteuler.net/problem=476
  2. Incircle and excentral geometry: Wikipedia — Incircle and excircles of a triangle
  3. Heron's formula: Wikipedia — Heron's formula
  4. Half-angle identities: Wikipedia — Half-angle formulae

Problemzusammenfassung

Sei

$$T_n=\left\{(a,b,c)\in \mathbb{Z}_{>0}^3:1\le a\le b\le c,\ c\le a+b-1,\ a+b\le n\right\}.$$

Für jedes ganzzahlige Dreieck aus \(T_n\) wird zuerst der Inkreis eingesetzt. Danach packt man in jeder Ecke weitere Kreise, die jeweils an den beiden Schenkeln des Winkels und am vorherigen Kreis derselben Ecke tangential liegen. Gemittelt wird die Fläche des Inkreises zusammen mit den zwei größten zusätzlichen Kreisen, die nach diesem ersten Schritt entstehen.

Bezeichnet \(F(a,b,c)\) diesen Dreiecksbeitrag, dann berechnen die Implementierungen

$$S(n)=\frac{1}{|T_n|}\sum_{(a,b,c)\in T_n} F(a,b,c).$$

Die verwendeten Kontrollwerte sind

$$S(2)=0.31998,\qquad S(5)=1.25899.$$

Mathematischer Ansatz

Fixiere ein Dreieck mit Seiten \(a\le b\le c\), und seien \(A\le B\le C\) die gegenüberliegenden Winkel. Die sortierte Seitenfolge ist wichtig, weil sie sofort verrät, in welchen Ecken die größten gepackten Kreise liegen können.

Schritt 1: Zulässige Dreiecke und Winkelordnung

Die Bedingungen

$$1\le a\le b\le c,\qquad c\le a+b-1,\qquad a+b\le n$$

bedeuten, dass über alle nicht entarteten ganzzahligen Dreiecke in sortierter Seitenreihenfolge gemittelt wird. Weil größere Seiten größeren Winkeln gegenüberliegen, gilt

$$A\le B\le C.$$

Gerade diese Ordnung steuert das Kreispacken: Ein kleinerer Winkel erzeugt den größeren nächsten Tangentialkreis. Deshalb liegt der größte Kreis nach dem Inkreis immer zuerst in der Ecke \(A\).

Schritt 2: Den Inkreisradius aus den Seiten berechnen

Setze

$$p=a+b+c,\qquad s=\frac{p}{2},\qquad x=p-2a,\qquad y=p-2b,\qquad z=p-2c.$$

Dann ist \(x=2(s-a)\), \(y=2(s-b)\) und \(z=2(s-c)\). Mit dem Flächeninhalt \(\Delta\) liefert die Formel von Heron

$$\Delta^2=s(s-a)(s-b)(s-c).$$

Für den Inkreisradius gilt \(r=\Delta/s\). Also folgt

$$r^2=\frac{\Delta^2}{s^2}=\frac{(s-a)(s-b)(s-c)}{s}=\frac{xyz}{4p}.$$

Genau diese kompakte Darstellung wird im Programm benutzt. So muss der Flächeninhalt nicht separat ausgerechnet werden, bevor am Ende mit \(\pi\) multipliziert wird.

Schritt 3: Das geometrische Verhältnis in einer Ecke herleiten

Betrachte einen Winkel \(\theta\). Jeder Kreis, der beide Schenkel dieses Winkels berührt, hat seinen Mittelpunkt auf der Winkelhalbierenden. Hat der Kreis Radius \(\rho\), so liegt sein Mittelpunkt im Abstand

$$d=\frac{\rho}{\sin(\theta/2)}$$

vom Eckpunkt.

Nehmen wir zwei aufeinanderfolgende Kreise derselben Ecke mit Radien \(R\) und \(R'\). Beide sind zu den Schenkeln tangential und zusätzlich zueinander tangential. Auf der Winkelhalbierenden gilt daher

$$\frac{R-R'}{\sin(\theta/2)}=R+R'.$$

Aufgelöst nach dem Verhältnis ergibt das

$$\frac{R'}{R}=\frac{1-\sin(\theta/2)}{1+\sin(\theta/2)}=:q(\theta).$$

Somit bildet jede Ecke eine geometrische Kette von Radien

$$r,\ rq(\theta),\ rq(\theta)^2,\ rq(\theta)^3,\dots$$

mit dem Inkreis als Startkreis. Für die beiden Winkel, die in der Endformel tatsächlich benötigt werden, gelten die Halbwinkelbeziehungen

$$\sin^2\left(\frac{A}{2}\right)=\frac{(s-b)(s-c)}{bc}=\frac{yz}{4bc},$$

$$\sin^2\left(\frac{B}{2}\right)=\frac{(s-a)(s-c)}{ac}=\frac{xz}{4ac}.$$

Schritt 4: Die zwei größten Zusatzkreise bestimmen

Die Funktion \(q(\theta)\) ist auf \((0,\pi)\) streng fallend. Aus \(A\le B\le C\) folgt deshalb

$$q_A\ge q_B\ge q_C,$$

wobei \(q_A=q(A)\), \(q_B=q(B)\) und \(q_C=q(C)\) ist.

Damit ist der größte Kreis nach dem Inkreis immer der erste Eckkreis im Winkel \(A\); sein Radius ist \(rq_A\).

Für den dritten ausgewählten Kreis bleiben nur zwei ernsthafte Kandidaten:

$$rq_B,\qquad rq_A^2.$$

Der erste Kreis in Ecke \(C\) ist höchstens so groß wie der erste Kreis in Ecke \(B\), und jeder spätere Kreis einer Ecke ist kleiner als der erste noch unbenutzte Kreis derselben Ecke. Also ist der dritte Radius

$$r\max\{q_B,q_A^2\}.$$

Für die Flächen benötigt man die Quadrate der Radien, also die beiden Zusatzfaktoren

$$q_A^2,\qquad \max\{q_B^2,q_A^4\}.$$

Schritt 5: Endformel für den Beitrag eines Dreiecks

Die Inkreisfläche ist \(\pi r^2\). Zusammen mit den zwei größten Zusatzkreisen ergibt sich

$$F(a,b,c)=\pi r^2\left(1+q_A^2+\max\{q_B^2,q_A^4\}\right).$$

Genau diese Größe wird für jedes zulässige Dreieck aufsummiert.

Durchgerechnetes Beispiel: Das gleichseitige Dreieck \((1,1,1)\)

Für \(a=b=c=1\) gilt

$$p=3,\qquad s=\frac{3}{2},\qquad x=y=z=1.$$

Daraus folgt

$$r^2=\frac{xyz}{4p}=\frac{1}{12}.$$

Alle Winkel sind gleich \(\pi/3\), also

$$\sin\left(\frac{A}{2}\right)=\sin\left(\frac{\pi}{6}\right)=\frac{1}{2},\qquad q_A=q_B=\frac{1-\frac12}{1+\frac12}=\frac13.$$

Somit erhält man

$$F(1,1,1)=\pi\cdot\frac{1}{12}\left(1+\frac{1}{9}+\max\left\{\frac{1}{9},\frac{1}{81}\right\}\right)=\pi\cdot\frac{1}{12}\left(1+\frac{1}{9}+\frac{1}{9}\right)=\frac{11\pi}{108}.$$

Numerisch ist das

$$\frac{11\pi}{108}\approx 0.31998.$$

Da \(T_2\) nur dieses eine Dreieck enthält, folgt \(S(2)=0.31998\), genau der Kontrollwert der Implementierung.

Wie der Code arbeitet

Die C++-, Python- und Java-Implementierungen werten dieselbe Formel aus. Sie durchlaufen alle zulässigen Dreiecke in sortierter Reihenfolge über \(a\), dann \(b\), dann alle passenden \(c\) mit

$$b\le c\le a+b-1.$$

Für jedes Dreieck berechnet die Implementierung \(p\), \(x\), \(y\) und \(z\), daraus \(r^2=xyz/(4p)\), anschließend die Halbwinkelterme für \(A\) und \(B\). Aus diesen Größen entstehen \(q_A\) und \(q_B\), und dann wird

$$\pi r^2\left(1+q_A^2+\max\{q_B^2,q_A^4\}\right)$$

zum laufenden Total addiert. Gleichzeitig wird die Zahl der Dreiecke mitgezählt.

Am Ende ist die gesuchte Größe einfach Gesamtfläche geteilt durch Dreiecksanzahl. Die Java-Implementierung verwendet eine kompensierte Summation, um Rundungsfehler zu dämpfen; die C++-Berechnung arbeitet mit erweiterter Genauigkeit. Die Python-Implementierung delegiert an dieselbe kompilierte Numerik, sodass alle drei Implementierungen dieselbe Geometrie und dieselben Kontrollwerte teilen.

Komplexitätsanalyse

Die Anzahl der zulässigen Dreiecke ist

$$|T_n|=\sum_{a=1}^{\lfloor n/2\rfloor}\sum_{b=a}^{n-a} a,$$

denn für festes \(a\) und \(b\) läuft \(c\) von \(b\) bis \(a+b-1\) und besitzt damit genau \(a\) Möglichkeiten. Diese Anzahl ist \(\Theta(n^3)\), also ist auch die Gesamtlaufzeit \(\Theta(n^3)\).

Pro Dreieck fallen nur konstante viele arithmetische Operationen, einige Quadratwurzeln und ein Maximum an. Der Speicherbedarf ist \(O(1)\), weil nur ein laufendes Total, ein Zähler und wenige temporäre Gleitkommazahlen gehalten werden.

Fußnoten und Referenzen

  1. Problemseite: https://projecteuler.net/problem=476
  2. Inkreis und Exkreise: Wikipedia — Incircle and excircles of a triangle
  3. Formel von Heron: Wikipedia — Heron's formula
  4. Halbwinkelformeln: Wikipedia — Half-angle formulae

Problem Özeti

Şunu tanımlayalım:

$$T_n=\left\{(a,b,c)\in \mathbb{Z}_{>0}^3:1\le a\le b\le c,\ c\le a+b-1,\ a+b\le n\right\}.$$

\(T_n\) içindeki her tam sayı üçgeni için önce içteğet çember yerleştirilir. Daha sonra her köşede, o açının iki kenarına ve aynı köşedeki bir önceki çembere teğet olacak şekilde yeni çemberler dizilir. Ortalaması alınan büyüklük, içteğet çember ile onun ardından gelen en büyük iki ek çemberin toplam alanıdır.

Bu üçgen katkısını \(F(a,b,c)\) ile gösterirsek, implementasyonlar

$$S(n)=\frac{1}{|T_n|}\sum_{(a,b,c)\in T_n} F(a,b,c)$$

değerini hesaplar. Kontrol noktaları

$$S(2)=0.31998,\qquad S(5)=1.25899$$

şeklindedir.

Matematiksel Yaklaşım

Şimdi \(a\le b\le c\) kenarlı sabit bir üçgen alalım ve karşı açılarını \(A\le B\le C\) diye adlandıralım. Kenarların sıralı olması, hangi köşelerde daha büyük paketleme çemberleri oluşacağını doğrudan belirler.

Adım 1: Uygun üçgenleri ve açı sırasını belirle

Koşullar

$$1\le a\le b\le c,\qquad c\le a+b-1,\qquad a+b\le n$$

bize sıralı kenarlara sahip, dejenerik olmayan tüm tam sayı üçgenler üzerinde ortalama aldığımızı söyler. Büyük kenarın karşısında büyük açı bulunduğu için

$$A\le B\le C$$

olur. Bu sıralama kritik önemdedir; çünkü daha dar bir köşe, bir sonraki teğet çember için daha büyük bir oran verir. Bu nedenle içteğet çemberden sonraki en büyük çember önce \(A\) köşesinde görünür.

Adım 2: İçteğet çember yarıçapını kenarlardan çıkar

Şöyle tanımlayalım:

$$p=a+b+c,\qquad s=\frac{p}{2},\qquad x=p-2a,\qquad y=p-2b,\qquad z=p-2c.$$

Böylece \(x=2(s-a)\), \(y=2(s-b)\) ve \(z=2(s-c)\) olur. Üçgen alanı \(\Delta\) için Heron formülü

$$\Delta^2=s(s-a)(s-b)(s-c)$$

der. İçteğet çember yarıçapı \(r=\Delta/s\) olduğuna göre

$$r^2=\frac{\Delta^2}{s^2}=\frac{(s-a)(s-b)(s-c)}{s}=\frac{xyz}{4p}$$

elde edilir. Implementasyonların kullandığı kısa form tam olarak budur; böylece alan ayrıca hesaplanmadan doğrudan \(r^2\) bulunur.

Adım 3: Tek bir köşedeki geometrik oranı türet

\(\theta\) açılı bir köşe düşünelim. Bu açının iki kenarına teğet olan her çemberin merkezi açıortay üzerindedir. Yarıçap \(\rho\) ise, merkezden köşeye uzaklık

$$d=\frac{\rho}{\sin(\theta/2)}$$

olur.

Aynı köşedeki ardışık iki çemberin yarıçapları \(R\) ve \(R'\) olsun. İkisi de kenarlara teğet ve birbirine dıştan teğet olduğu için açıortay üzerinde

$$\frac{R-R'}{\sin(\theta/2)}=R+R'$$

eşitliği sağlanır. Buradan

$$\frac{R'}{R}=\frac{1-\sin(\theta/2)}{1+\sin(\theta/2)}=:q(\theta)$$

çıkar. Yani her köşede yarıçaplar

$$r,\ rq(\theta),\ rq(\theta)^2,\ rq(\theta)^3,\dots$$

şeklinde geometrik bir zincir oluşturur. Son karşılaştırmada gerçekten gereken iki açı için yarım-açı özdeşlikleri

$$\sin^2\left(\frac{A}{2}\right)=\frac{(s-b)(s-c)}{bc}=\frac{yz}{4bc},$$

$$\sin^2\left(\frac{B}{2}\right)=\frac{(s-a)(s-c)}{ac}=\frac{xz}{4ac}$$

şeklindedir.

Adım 4: En büyük iki ek çemberi belirle

\(q(\theta)\) fonksiyonu \((0,\pi)\) aralığında açı büyüdükçe azalır. \(A\le B\le C\) olduğundan

$$q_A\ge q_B\ge q_C$$

elde edilir; burada \(q_A=q(A)\), \(q_B=q(B)\), \(q_C=q(C)\).

Dolayısıyla içteğet çemberden sonraki en büyük çember her zaman \(A\) köşesindeki ilk çemberdir ve yarıçapı \(rq_A\)'dır.

Üçüncü seçilen çember için geriye sadece iki ciddi aday kalır:

$$rq_B,\qquad rq_A^2.$$

\(C\) köşesindeki ilk çember, \(B\) köşesindekinden büyük olamaz; herhangi bir köşedeki daha sonraki çemberler de o köşedeki ilk kullanılmayan çemberden daha küçük olur. Bu yüzden üçüncü yarıçap

$$r\max\{q_B,q_A^2\}$$

olur. Alan hesabında ise yarıçap kareleri gerektiğinden iki ek katkı

$$q_A^2,\qquad \max\{q_B^2,q_A^4\}$$

şeklindedir.

Adım 5: Bir üçgenin son katkı formülü

İçteğet çember alanı \(\pi r^2\)'dir. Buna iki büyük ek çember eklendiğinde

$$F(a,b,c)=\pi r^2\left(1+q_A^2+\max\{q_B^2,q_A^4\}\right)$$

elde edilir. Implementasyonların her uygun üçgen için topladığı büyüklük tam olarak budur.

Çözümlü Örnek: Eşkenar üçgen \((1,1,1)\)

\(a=b=c=1\) için

$$p=3,\qquad s=\frac{3}{2},\qquad x=y=z=1$$

olur. Buradan

$$r^2=\frac{xyz}{4p}=\frac{1}{12}$$

çıkar. Tüm açılar \(\pi/3\) olduğundan

$$\sin\left(\frac{A}{2}\right)=\sin\left(\frac{\pi}{6}\right)=\frac{1}{2},\qquad q_A=q_B=\frac{1-\frac12}{1+\frac12}=\frac13.$$

Dolayısıyla

$$F(1,1,1)=\pi\cdot\frac{1}{12}\left(1+\frac{1}{9}+\max\left\{\frac{1}{9},\frac{1}{81}\right\}\right)=\pi\cdot\frac{1}{12}\left(1+\frac{1}{9}+\frac{1}{9}\right)=\frac{11\pi}{108}$$

ve sayısal olarak

$$\frac{11\pi}{108}\approx 0.31998$$

bulunur. \(T_2\) kümesinde yalnızca bu üçgen bulunduğu için \(S(2)=0.31998\) kontrolü doğrudan sağlanır.

Kod Nasıl Çalışır

C++, Python ve Java implementasyonları aynı formülü değerlendirir. Önce \(a\), sonra \(b\), sonra da

$$b\le c\le a+b-1$$

koşulunu sağlayan tüm \(c\) değerleri dolaşılarak sıralı uygun üçgenler üretilir.

Her üçgen için implementasyon \(p\), \(x\), \(y\), \(z\) değerlerini hesaplar; bunlardan \(r^2=xyz/(4p)\) bulunur; ardından \(A\) ve \(B\) açıları için yarım-açı terimleri hesaplanır. Sonra \(q_A\) ve \(q_B\) elde edilip

$$\pi r^2\left(1+q_A^2+\max\{q_B^2,q_A^4\}\right)$$

çalışan toplama eklenir ve üçgen sayacı artırılır.

Son aşamada toplam, üçgen sayısına bölünür. Java implementasyonu kayan nokta kaybını azaltmak için telafili toplama kullanır; C++ tarafı genişletilmiş hassasiyetle hesap yapar. Python implementasyonu aynı derlenmiş sayısal rutine dayandığı için üçü de aynı geometriyi ve aynı kontrol noktalarını paylaşır.

Karmaşıklık Analizi

Uygun üçgen sayısı

$$|T_n|=\sum_{a=1}^{\lfloor n/2\rfloor}\sum_{b=a}^{n-a} a$$

şeklindedir; çünkü sabit \(a\) ve \(b\) için \(c\), \(b\) ile \(a+b-1\) arasında tam olarak \(a\) farklı değer alır. Bu sayı \(\Theta(n^3)\) mertebesindedir; dolayısıyla toplam çalışma süresi de \(\Theta(n^3)\) olur.

Her üçgen için yapılan iş sabit sayıda aritmetik işlem, birkaç karekök ve bir maksimum karşılaştırmasından ibarettir. Bellek kullanımı \(O(1)\)'dir; sadece çalışan toplam, sayaç ve birkaç geçici kayan nokta değeri tutulur.

Dipnotlar ve Kaynaklar

  1. Problem sayfası: https://projecteuler.net/problem=476
  2. İçteğet çember ve dışteğet çemberler: Wikipedia — Incircle and excircles of a triangle
  3. Heron formülü: Wikipedia — Heron's formula
  4. Yarım-açı formülleri: Wikipedia — Half-angle formulae

Resumen del Problema

Definamos

$$T_n=\left\{(a,b,c)\in \mathbb{Z}_{>0}^3:1\le a\le b\le c,\ c\le a+b-1,\ a+b\le n\right\}.$$

Para cada triángulo entero de \(T_n\), primero se coloca el incírculo. Después, en cada vértice, se siguen empaquetando círculos tangentes a los dos lados de ese ángulo y al círculo anterior de la misma cadena. La cantidad que se promedia es el área del incírculo junto con los dos círculos adicionales más grandes que aparecen después de esa primera colocación.

Si llamamos \(F(a,b,c)\) a la contribución de un triángulo, las implementaciones calculan

$$S(n)=\frac{1}{|T_n|}\sum_{(a,b,c)\in T_n} F(a,b,c).$$

Los valores de comprobación son

$$S(2)=0.31998,\qquad S(5)=1.25899.$$

Enfoque Matemático

Fijemos un triángulo con lados \(a\le b\le c\), y sean \(A\le B\le C\) los ángulos opuestos. El orden de los lados ya indica qué vértices pueden producir los círculos empaquetados más grandes.

Paso 1: Describir los triángulos válidos y el orden de los ángulos

Las desigualdades

$$1\le a\le b\le c,\qquad c\le a+b-1,\qquad a+b\le n$$

dicen que se promedia sobre todos los triángulos enteros no degenerados en orden de lados creciente. Como un lado mayor se enfrenta a un ángulo mayor, tenemos

$$A\le B\le C.$$

Esta observación es esencial: un ángulo más estrecho genera un siguiente círculo tangente más grande. Por eso, después del incírculo, el mayor círculo extra siempre aparece primero en el ángulo \(A\).

Paso 2: Obtener el radio del incírculo a partir de los lados

Definimos

$$p=a+b+c,\qquad s=\frac{p}{2},\qquad x=p-2a,\qquad y=p-2b,\qquad z=p-2c.$$

Entonces \(x=2(s-a)\), \(y=2(s-b)\) y \(z=2(s-c)\). Si \(\Delta\) es el área del triángulo, la fórmula de Herón da

$$\Delta^2=s(s-a)(s-b)(s-c).$$

Como el inradio es \(r=\Delta/s\), se obtiene

$$r^2=\frac{\Delta^2}{s^2}=\frac{(s-a)(s-b)(s-c)}{s}=\frac{xyz}{4p}.$$

Ésta es exactamente la forma compacta que usan las implementaciones. Así se evita recomputar el área antes de multiplicar por \(\pi\).

Paso 3: Derivar la razón geométrica dentro de un vértice

Consideremos un ángulo \(\theta\). Todo círculo tangente a los dos lados de ese ángulo tiene su centro sobre la bisectriz. Si su radio es \(\rho\), la distancia del centro al vértice es

$$d=\frac{\rho}{\sin(\theta/2)}.$$

Tomemos ahora dos círculos consecutivos de la misma esquina, con radios \(R\) y \(R'\). Ambos son tangentes a los lados y además tangentes entre sí. Sobre la bisectriz se cumple

$$\frac{R-R'}{\sin(\theta/2)}=R+R'.$$

y al despejar aparece la razón

$$\frac{R'}{R}=\frac{1-\sin(\theta/2)}{1+\sin(\theta/2)}=:q(\theta).$$

Por tanto, cada vértice genera una cadena geométrica de radios

$$r,\ rq(\theta),\ rq(\theta)^2,\ rq(\theta)^3,\dots$$

a partir del incírculo. Para los dos ángulos que sí entran en la fórmula final, las identidades de medio ángulo son

$$\sin^2\left(\frac{A}{2}\right)=\frac{(s-b)(s-c)}{bc}=\frac{yz}{4bc},$$

$$\sin^2\left(\frac{B}{2}\right)=\frac{(s-a)(s-c)}{ac}=\frac{xz}{4ac}.$$

Paso 4: Determinar los dos mayores círculos extra

La función \(q(\theta)\) decrece cuando \(\theta\) aumenta en \((0,\pi)\). Como \(A\le B\le C\), resulta

$$q_A\ge q_B\ge q_C,$$

donde \(q_A=q(A)\), \(q_B=q(B)\) y \(q_C=q(C)\).

Así, el mayor círculo después del incírculo es siempre el primero de la esquina \(A\), con radio \(rq_A\).

Para el tercer círculo elegido sólo sobreviven dos candidatos reales:

$$rq_B,\qquad rq_A^2.$$

El primer círculo de la esquina \(C\) no puede superar al primero de la esquina \(B\), y cualquier círculo posterior de una esquina es menor que el primer círculo no usado de esa misma esquina. En consecuencia, el tercer radio es

$$r\max\{q_B,q_A^2\}.$$

Al pasar de radios a áreas, los dos factores extra son

$$q_A^2,\qquad \max\{q_B^2,q_A^4\}.$$

Paso 5: Fórmula final para la contribución de un triángulo

El área del incírculo es \(\pi r^2\). Sumando los dos mayores círculos extra, obtenemos

$$F(a,b,c)=\pi r^2\left(1+q_A^2+\max\{q_B^2,q_A^4\}\right).$$

Ésta es exactamente la cantidad acumulada por las implementaciones para cada triángulo válido.

Ejemplo trabajado: El triángulo equilátero \((1,1,1)\)

Para \(a=b=c=1\), se tiene

$$p=3,\qquad s=\frac{3}{2},\qquad x=y=z=1.$$

Por tanto,

$$r^2=\frac{xyz}{4p}=\frac{1}{12}.$$

Todos los ángulos valen \(\pi/3\), luego

$$\sin\left(\frac{A}{2}\right)=\sin\left(\frac{\pi}{6}\right)=\frac{1}{2},\qquad q_A=q_B=\frac{1-\frac12}{1+\frac12}=\frac13.$$

Entonces

$$F(1,1,1)=\pi\cdot\frac{1}{12}\left(1+\frac{1}{9}+\max\left\{\frac{1}{9},\frac{1}{81}\right\}\right)=\pi\cdot\frac{1}{12}\left(1+\frac{1}{9}+\frac{1}{9}\right)=\frac{11\pi}{108}.$$

Numéricamente,

$$\frac{11\pi}{108}\approx 0.31998.$$

Como \(T_2\) contiene sólo este triángulo, se obtiene \(S(2)=0.31998\), exactamente el valor de comprobación.

Cómo Funciona el Código

Las implementaciones en C++, Python y Java evalúan la misma fórmula. Recorren todos los triángulos válidos en orden, iterando primero sobre \(a\), luego sobre \(b\), y finalmente sobre todos los \(c\) que satisfacen

$$b\le c\le a+b-1.$$

Para cada triángulo, la implementación calcula \(p\), \(x\), \(y\) y \(z\), obtiene \(r^2=xyz/(4p)\), evalúa los términos de medio ángulo necesarios para \(A\) y \(B\), forma \(q_A\) y \(q_B\), y después suma

$$\pi r^2\left(1+q_A^2+\max\{q_B^2,q_A^4\}\right)$$

a un total acumulado, además de incrementar el contador de triángulos.

El resultado final es el total dividido por el número de triángulos. La implementación en Java usa una suma compensada para reducir la pérdida de precisión en coma flotante, mientras que la de C++ trabaja con precisión extendida. La implementación en Python delega en la misma rutina numérica compilada, por lo que las tres comparten la misma geometría y los mismos puntos de control.

Complejidad

El número de triángulos válidos es

$$|T_n|=\sum_{a=1}^{\lfloor n/2\rfloor}\sum_{b=a}^{n-a} a,$$

porque para \(a\) y \(b\) fijos, el valor de \(c\) recorre desde \(b\) hasta \(a+b-1\), lo que da exactamente \(a\) posibilidades. Esta cantidad es \(\Theta(n^3)\), de modo que el tiempo total también es \(\Theta(n^3)\).

El trabajo por triángulo es constante: algunas operaciones aritméticas, unas pocas raíces cuadradas y una comparación de máximo. El uso de memoria es \(O(1)\), ya que sólo se mantienen un total acumulado, un contador y unas cuantas variables temporales de punto flotante.

Notas y Referencias

  1. Página del problema: https://projecteuler.net/problem=476
  2. Incírculo y excírculos: Wikipedia — Incircle and excircles of a triangle
  3. Fórmula de Herón: Wikipedia — Heron's formula
  4. Fórmulas de medio ángulo: Wikipedia — Half-angle formulae

问题概述

定义

$$T_n=\left\{(a,b,c)\in \mathbb{Z}_{>0}^3:1\le a\le b\le c,\ c\le a+b-1,\ a+b\le n\right\}.$$

对 \(T_n\) 中的每个整数三角形,先放入内切圆。然后在每一个顶角里继续放置一串圆:每个新圆都同时与该角的两条边以及该角中前一个圆相切。程序取平均的量,是“内切圆面积 + 放完内切圆之后出现的两个最大附加圆的面积”。

如果把单个三角形的贡献记作 \(F(a,b,c)\),那么实现计算的是

$$S(n)=\frac{1}{|T_n|}\sum_{(a,b,c)\in T_n} F(a,b,c).$$

实现中使用的数值校验点是

$$S(2)=0.31998,\qquad S(5)=1.25899.$$

数学方法

固定一个边长满足 \(a\le b\le c\) 的三角形,记其对角为 \(A\le B\le C\)。边的排序并不是装饰信息,它直接决定了哪个角里会出现更大的相切圆。

步骤 1:写清楚被平均的三角形集合和角的顺序

条件

$$1\le a\le b\le c,\qquad c\le a+b-1,\qquad a+b\le n$$

表示我们在所有按边长升序写出的非退化整数三角形上取平均。因为边越长,对应的角越大,所以必然有

$$A\le B\le C.$$

这一点非常关键:角越小,下一颗能塞进去的相切圆反而越大。因此在放好内切圆以后,最大的附加圆一定先出现在最小角 \(A\) 处。

步骤 2:由边长求内切圆半径

$$p=a+b+c,\qquad s=\frac{p}{2},\qquad x=p-2a,\qquad y=p-2b,\qquad z=p-2c.$$

于是 \(x=2(s-a)\)、\(y=2(s-b)\)、\(z=2(s-c)\)。若三角形面积为 \(\Delta\),Heron 公式给出

$$\Delta^2=s(s-a)(s-b)(s-c).$$

内切圆半径满足 \(r=\Delta/s\),因此

$$r^2=\frac{\Delta^2}{s^2}=\frac{(s-a)(s-b)(s-c)}{s}=\frac{xyz}{4p}.$$

这正是实现中采用的紧凑表达式。这样一来,在最后乘上 \(\pi\) 之前,不需要先显式求出三角形面积。

步骤 3:推导单个角里圆链的几何比

考虑某个角 \(\theta\)。凡是同时与这个角的两条边相切的圆,其圆心都落在角平分线上。若该圆半径为 \(\rho\),则圆心到顶点的距离为

$$d=\frac{\rho}{\sin(\theta/2)}.$$

现在取同一角内相邻的两个圆,半径分别为 \(R\) 与 \(R'\)。它们都与两边相切,并且彼此外切,因此沿角平分线有

$$\frac{R-R'}{\sin(\theta/2)}=R+R'.$$

解出比例可得

$$\frac{R'}{R}=\frac{1-\sin(\theta/2)}{1+\sin(\theta/2)}=:q(\theta).$$

所以,以内切圆为起点,每个角都会生成一个半径的等比数列

$$r,\ rq(\theta),\ rq(\theta)^2,\ rq(\theta)^3,\dots$$

在最终公式里,真正需要显式计算的只有 \(A\) 和 \(B\) 两个角。它们的半角公式为

$$\sin^2\left(\frac{A}{2}\right)=\frac{(s-b)(s-c)}{bc}=\frac{yz}{4bc},$$

$$\sin^2\left(\frac{B}{2}\right)=\frac{(s-a)(s-c)}{ac}=\frac{xz}{4ac}.$$

步骤 4:判断哪两个附加圆最大

函数 \(q(\theta)\) 在 \((0,\pi)\) 上随 \(\theta\) 增大而减小。由于 \(A\le B\le C\),所以

$$q_A\ge q_B\ge q_C,$$

其中 \(q_A=q(A)\)、\(q_B=q(B)\)、\(q_C=q(C)\)。

因此,内切圆之后最大的附加圆一定是角 \(A\) 里的第一颗圆,它的半径是 \(rq_A\)。

接下来要选第三颗圆时,真正可能胜出的只剩两个候选:

$$rq_B,\qquad rq_A^2.$$

原因是:角 \(C\) 的第一颗圆不可能比角 \(B\) 的第一颗圆更大;而任何角里的后续圆都不会超过该角中尚未使用的第一颗圆。所以第三颗圆的半径就是

$$r\max\{q_B,q_A^2\}.$$

从半径转成面积时需要平方,因此两个附加面积因子为

$$q_A^2,\qquad \max\{q_B^2,q_A^4\}.$$

步骤 5:单个三角形的最终贡献公式

内切圆面积是 \(\pi r^2\)。再加上两个最大的附加圆后,得到

$$F(a,b,c)=\pi r^2\left(1+q_A^2+\max\{q_B^2,q_A^4\}\right).$$

实现对每个合法三角形累加的正是这一个表达式。

例子:等边三角形 \((1,1,1)\)

当 \(a=b=c=1\) 时,有

$$p=3,\qquad s=\frac{3}{2},\qquad x=y=z=1.$$

于是

$$r^2=\frac{xyz}{4p}=\frac{1}{12}.$$

三个角都等于 \(\pi/3\),因此

$$\sin\left(\frac{A}{2}\right)=\sin\left(\frac{\pi}{6}\right)=\frac{1}{2},\qquad q_A=q_B=\frac{1-\frac12}{1+\frac12}=\frac13.$$

代入后得到

$$F(1,1,1)=\pi\cdot\frac{1}{12}\left(1+\frac{1}{9}+\max\left\{\frac{1}{9},\frac{1}{81}\right\}\right)=\pi\cdot\frac{1}{12}\left(1+\frac{1}{9}+\frac{1}{9}\right)=\frac{11\pi}{108}.$$

数值上

$$\frac{11\pi}{108}\approx 0.31998.$$

而 \(T_2\) 中只有这一个三角形,所以 \(S(2)=0.31998\),恰好与实现中的检查值一致。

代码如何工作

C++、Python 和 Java 实现都在计算同一条公式。它们按顺序枚举所有合法三角形:先枚举 \(a\),再枚举 \(b\),最后枚举满足

$$b\le c\le a+b-1$$

的所有 \(c\)。

对于每个三角形,实现先求出 \(p\)、\(x\)、\(y\)、\(z\),再由此得到 \(r^2=xyz/(4p)\),接着计算 \(A\) 与 \(B\) 所需的半角量,构造出 \(q_A\) 和 \(q_B\),然后把

$$\pi r^2\left(1+q_A^2+\max\{q_B^2,q_A^4\}\right)$$

加入累计总和,并把三角形计数器加一。

最后用总和除以三角形总数,就得到 \(S(n)\)。Java 实现使用补偿求和来减轻浮点累加误差,C++ 计算使用扩展精度;Python 实现则委托给同一套编译后的数值计算,因此三者共享完全相同的几何公式与校验点。

复杂度分析

合法三角形总数为

$$|T_n|=\sum_{a=1}^{\lfloor n/2\rfloor}\sum_{b=a}^{n-a} a,$$

因为在固定 \(a\) 和 \(b\) 时,\(c\) 从 \(b\) 取到 \(a+b-1\),正好有 \(a\) 个选择。这个数量级是 \(\Theta(n^3)\),因此总运行时间也是 \(\Theta(n^3)\)。

每个三角形只需要常数次算术运算、若干次平方根以及一次最大值比较。空间复杂度为 \(O(1)\),因为实现只维护累计总和、计数器和少量临时浮点变量。

注释与参考

  1. 题目页面: https://projecteuler.net/problem=476
  2. 内切圆与旁切圆: Wikipedia — Incircle and excircles of a triangle
  3. Heron 公式: Wikipedia — Heron's formula
  4. 半角恒等式: Wikipedia — Half-angle formulae

Краткое описание задачи

Определим

$$T_n=\left\{(a,b,c)\in \mathbb{Z}_{>0}^3:1\le a\le b\le c,\ c\le a+b-1,\ a+b\le n\right\}.$$

Для каждого целочисленного треугольника из \(T_n\) сначала строится вписанная окружность. Затем в каждом углу продолжается упаковка окружностей: каждая новая окружность касается двух сторон этого угла и предыдущей окружности в той же угловой цепочке. Усредняется площадь вписанной окружности вместе с двумя наибольшими дополнительными окружностями, которые появляются после первого шага.

Если вклад одного треугольника обозначить через \(F(a,b,c)\), то реализации вычисляют

$$S(n)=\frac{1}{|T_n|}\sum_{(a,b,c)\in T_n} F(a,b,c).$$

Контрольные значения таковы:

$$S(2)=0.31998,\qquad S(5)=1.25899.$$

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

Зафиксируем треугольник со сторонами \(a\le b\le c\), а противоположные углы обозначим через \(A\le B\le C\). Порядок сторон здесь важен, потому что он сразу показывает, в каких углах могут стоять самые большие упакованные окружности.

Шаг 1: Описать допустимые треугольники и порядок углов

Условия

$$1\le a\le b\le c,\qquad c\le a+b-1,\qquad a+b\le n$$

означают, что усреднение ведется по всем невырожденным целочисленным треугольникам, записанным в неубывающем порядке сторон. Поскольку большей стороне противолежит больший угол, имеем

$$A\le B\le C.$$

Это ключевое наблюдение: чем уже угол, тем больше следующий касающийся круг. Поэтому после вписанной окружности самый крупный дополнительный круг всегда появляется сначала в угле \(A\).

Шаг 2: Выразить радиус вписанной окружности через стороны

Введем обозначения

$$p=a+b+c,\qquad s=\frac{p}{2},\qquad x=p-2a,\qquad y=p-2b,\qquad z=p-2c.$$

Тогда \(x=2(s-a)\), \(y=2(s-b)\), \(z=2(s-c)\). Если \(\Delta\) обозначает площадь треугольника, то по формуле Герона

$$\Delta^2=s(s-a)(s-b)(s-c).$$

Радиус вписанной окружности равен \(r=\Delta/s\), следовательно

$$r^2=\frac{\Delta^2}{s^2}=\frac{(s-a)(s-b)(s-c)}{s}=\frac{xyz}{4p}.$$

Именно эта компактная формула используется в реализациях. Она позволяет получить \(r^2\) напрямую, без отдельного вычисления площади перед финальным умножением на \(\pi\).

Шаг 3: Вывести геометрическое отношение в одном углу

Рассмотрим угол \(\theta\). Любая окружность, касающаяся обеих его сторон, имеет центр на биссектрисе. Если ее радиус равен \(\rho\), то расстояние от центра до вершины равно

$$d=\frac{\rho}{\sin(\theta/2)}.$$

Теперь возьмем две соседние окружности одной угловой цепочки с радиусами \(R\) и \(R'\). Обе касаются сторон угла и касаются друг друга, поэтому на биссектрисе выполняется

$$\frac{R-R'}{\sin(\theta/2)}=R+R'.$$

Отсюда получаем отношение

$$\frac{R'}{R}=\frac{1-\sin(\theta/2)}{1+\sin(\theta/2)}=:q(\theta).$$

Значит, в каждом углу возникает геометрическая цепочка радиусов

$$r,\ rq(\theta),\ rq(\theta)^2,\ rq(\theta)^3,\dots$$

со стартом во вписанной окружности. Для двух углов, которые действительно нужны в окончательной формуле, полуугловые тождества имеют вид

$$\sin^2\left(\frac{A}{2}\right)=\frac{(s-b)(s-c)}{bc}=\frac{yz}{4bc},$$

$$\sin^2\left(\frac{B}{2}\right)=\frac{(s-a)(s-c)}{ac}=\frac{xz}{4ac}.$$

Шаг 4: Определить две крупнейшие дополнительные окружности

Функция \(q(\theta)\) убывает при росте \(\theta\) на интервале \((0,\pi)\). Поэтому из \(A\le B\le C\) следует

$$q_A\ge q_B\ge q_C,$$

где \(q_A=q(A)\), \(q_B=q(B)\), \(q_C=q(C)\).

Следовательно, самая большая окружность после вписанной окружности всегда находится в угле \(A\) и имеет радиус \(rq_A\).

Для третьей выбранной окружности остаются только два реальных кандидата:

$$rq_B,\qquad rq_A^2.$$

Первая окружность в угле \(C\) не превосходит первую окружность в угле \(B\), а любая следующая окружность в любом углу меньше первой еще не выбранной окружности этого угла. Значит, третий радиус равен

$$r\max\{q_B,q_A^2\}.$$

При переходе к площадям нужно возвести радиусы в квадрат, так что два дополнительных множителя равны

$$q_A^2,\qquad \max\{q_B^2,q_A^4\}.$$

Шаг 5: Итоговая формула вклада одного треугольника

Площадь вписанной окружности равна \(\pi r^2\). Добавляя две крупнейшие дополнительные окружности, получаем

$$F(a,b,c)=\pi r^2\left(1+q_A^2+\max\{q_B^2,q_A^4\}\right).$$

Именно это выражение накапливают реализации для каждого допустимого треугольника.

Разобранный пример: Равносторонний треугольник \((1,1,1)\)

Если \(a=b=c=1\), то

$$p=3,\qquad s=\frac{3}{2},\qquad x=y=z=1.$$

Поэтому

$$r^2=\frac{xyz}{4p}=\frac{1}{12}.$$

Все углы равны \(\pi/3\), а значит

$$\sin\left(\frac{A}{2}\right)=\sin\left(\frac{\pi}{6}\right)=\frac{1}{2},\qquad q_A=q_B=\frac{1-\frac12}{1+\frac12}=\frac13.$$

Тогда

$$F(1,1,1)=\pi\cdot\frac{1}{12}\left(1+\frac{1}{9}+\max\left\{\frac{1}{9},\frac{1}{81}\right\}\right)=\pi\cdot\frac{1}{12}\left(1+\frac{1}{9}+\frac{1}{9}\right)=\frac{11\pi}{108}.$$

Численно

$$\frac{11\pi}{108}\approx 0.31998.$$

Так как \(T_2\) состоит ровно из одного этого треугольника, сразу получаем \(S(2)=0.31998\), что совпадает с контрольной проверкой.

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

Реализации на C++, Python и Java вычисляют одну и ту же формулу. Они перечисляют все допустимые треугольники в упорядоченном виде: сначала выбирают \(a\), затем \(b\), затем все возможные \(c\), удовлетворяющие

$$b\le c\le a+b-1.$$

Для каждого треугольника реализация находит \(p\), \(x\), \(y\), \(z\), затем вычисляет \(r^2=xyz/(4p)\), после чего считает полуугловые величины для \(A\) и \(B\), строит \(q_A\) и \(q_B\) и добавляет в накопленную сумму

$$\pi r^2\left(1+q_A^2+\max\{q_B^2,q_A^4\}\right).$$

Одновременно увеличивается счетчик треугольников.

В конце общая сумма делится на число треугольников. Реализация на Java использует компенсированное суммирование, чтобы уменьшить потери точности при накоплении, а вычисление на C++ ведется с расширенной точностью. Реализация на Python опирается на ту же скомпилированную численную процедуру, поэтому во всех трех случаях используются одна и та же геометрия и те же контрольные значения.

Анализ сложности

Количество допустимых треугольников равно

$$|T_n|=\sum_{a=1}^{\lfloor n/2\rfloor}\sum_{b=a}^{n-a} a,$$

потому что при фиксированных \(a\) и \(b\) значение \(c\) пробегает от \(b\) до \(a+b-1\), то есть имеет ровно \(a\) вариантов. Эта величина имеет порядок \(\Theta(n^3)\), и потому общее время работы также равно \(\Theta(n^3)\).

На каждый треугольник приходится постоянное число арифметических действий, несколько квадратных корней и одно сравнение. Память имеет сложность \(O(1)\), так как хранятся только накопленная сумма, счетчик и несколько временных чисел с плавающей точкой.

Сноски и Ссылки

  1. Страница задачи: https://projecteuler.net/problem=476
  2. Вписанная и вневписанные окружности: Wikipedia — Incircle and excircles of a triangle
  3. Формула Герона: Wikipedia — Heron's formula
  4. Формулы половинного угла: Wikipedia — Half-angle formulae

ملخص المسألة

لنعرّف المجموعة

$$T_n=\left\{(a,b,c)\in \mathbb{Z}_{>0}^3:1\le a\le b\le c,\ c\le a+b-1,\ a+b\le n\right\}.$$

لكل مثلث صحيح في \(T_n\) نضع أولًا الدائرة الداخلية. بعد ذلك نتابع في كل زاوية حشر دوائر جديدة بحيث تكون كل دائرة مماسةً لضلعَي تلك الزاوية وللدائرة السابقة في السلسلة نفسها. الكمية التي يُؤخذ متوسطها هي مساحة الدائرة الداخلية مع أكبر دائرتين إضافيتين تظهران بعد هذه الخطوة الأولى.

إذا رمزنا إلى مساهمة مثلث واحد بـ \(F(a,b,c)\)، فإن التنفيذات تحسب

$$S(n)=\frac{1}{|T_n|}\sum_{(a,b,c)\in T_n} F(a,b,c).$$

ونقطتا التحقق العدديتان هما

$$S(2)=0.31998,\qquad S(5)=1.25899.$$

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

ثبّت مثلثًا أطوال أضلاعه \(a\le b\le c\)، ولتكن الزوايا المقابلة هي \(A\le B\le C\). ترتيب الأضلاع هنا مهم لأنه يحدد مباشرةً أي الزوايا يمكن أن تعطي أكبر الدوائر المعبأة.

الخطوة 1: وصف المثلثات المسموح بها وترتيب الزوايا

القيود

$$1\le a\le b\le c,\qquad c\le a+b-1,\qquad a+b\le n$$

تعني أننا نأخذ المتوسط على جميع المثلثات الصحيحة غير المنعدمة بعد ترتيب الأضلاع تصاعديًا. وبما أن الضلع الأكبر يقابله زاوية أكبر، فإن

$$A\le B\le C.$$

وهذه الملاحظة هي جوهر الاختيار: الزاوية الأضيق تنتج دائرة مماسة تالية أكبر. لذلك فإن أكبر دائرة بعد الدائرة الداخلية تظهر أولًا في الزاوية \(A\).

الخطوة 2: استخراج نصف قطر الدائرة الداخلية من الأضلاع

نضع

$$p=a+b+c,\qquad s=\frac{p}{2},\qquad x=p-2a,\qquad y=p-2b,\qquad z=p-2c.$$

وعندئذٍ \(x=2(s-a)\) و\(y=2(s-b)\) و\(z=2(s-c)\). إذا كانت مساحة المثلث هي \(\Delta\)، فإن صيغة هيرون تعطي

$$\Delta^2=s(s-a)(s-b)(s-c).$$

ونصف قطر الدائرة الداخلية هو \(r=\Delta/s\)، ومنه

$$r^2=\frac{\Delta^2}{s^2}=\frac{(s-a)(s-b)(s-c)}{s}=\frac{xyz}{4p}.$$

وهذه هي الصيغة المختصرة نفسها التي يستعملها التنفيذ. فهي تعطي \(r^2\) مباشرةً من الأضلاع دون الحاجة إلى حساب المساحة صراحةً قبل الضرب في \(\pi\).

الخطوة 3: اشتقاق النسبة الهندسية داخل زاوية واحدة

لننظر إلى زاوية مقدارها \(\theta\). كل دائرة تمس ضلعي هذه الزاوية يكون مركزها على منصف الزاوية. إذا كان نصف قطرها \(\rho\)، فإن بُعد مركزها عن الرأس يساوي

$$d=\frac{\rho}{\sin(\theta/2)}.$$

خذ دائرتين متتاليتين في السلسلة نفسها بنصفي قطر \(R\) و\(R'\). كلتاهما تمسان الضلعين وتمسان إحداهما الأخرى، ولذلك يتحقق على منصف الزاوية

$$\frac{R-R'}{\sin(\theta/2)}=R+R'.$$

ومنها نحصل على النسبة

$$\frac{R'}{R}=\frac{1-\sin(\theta/2)}{1+\sin(\theta/2)}=:q(\theta).$$

إذن كل زاوية تولّد سلسلة هندسية من أنصاف الأقطار

$$r,\ rq(\theta),\ rq(\theta)^2,\ rq(\theta)^3,\dots$$

تبدأ من الدائرة الداخلية. أما الزاويتان اللتان نحتاجهما صراحةً في الصيغة النهائية فلهما علاقات نصف الزاوية

$$\sin^2\left(\frac{A}{2}\right)=\frac{(s-b)(s-c)}{bc}=\frac{yz}{4bc},$$

$$\sin^2\left(\frac{B}{2}\right)=\frac{(s-a)(s-c)}{ac}=\frac{xz}{4ac}.$$

الخطوة 4: تحديد أكبر دائرتين إضافيتين

الدالة \(q(\theta)\) تتناقص عندما تزداد \(\theta\) على المجال \((0,\pi)\). ومن ثم، بما أن \(A\le B\le C\)، نحصل على

$$q_A\ge q_B\ge q_C,$$

حيث \(q_A=q(A)\) و\(q_B=q(B)\) و\(q_C=q(C)\).

إذن أكبر دائرة بعد الدائرة الداخلية هي دائمًا أول دائرة في الزاوية \(A\)، ونصف قطرها \(rq_A\).

أما الدائرة الثالثة المختارة فلا يبقى لها إلا مرشحان حقيقيان:

$$rq_B,\qquad rq_A^2.$$

فأول دائرة في الزاوية \(C\) لا يمكن أن تكون أكبر من أول دائرة في الزاوية \(B\)، وأي دائرة لاحقة في أي زاوية أصغر من أول دائرة غير مستخدمة في تلك الزاوية. لذا فإن نصف القطر الثالث يساوي

$$r\max\{q_B,q_A^2\}.$$

وعند التحويل إلى مساحات نحتاج إلى مربعات أنصاف الأقطار، فتكون العبارتان الإضافيتان هما

$$q_A^2,\qquad \max\{q_B^2,q_A^4\}.$$

الخطوة 5: الصيغة النهائية لمساهمة مثلث واحد

مساحة الدائرة الداخلية هي \(\pi r^2\). وبعد إضافة أكبر دائرتين إضافيتين نحصل على

$$F(a,b,c)=\pi r^2\left(1+q_A^2+\max\{q_B^2,q_A^4\}\right).$$

وهذه هي الكمية التي تجمعها التنفيذات لكل مثلث مسموح به.

مثال محلول: المثلث المتساوي الأضلاع \((1,1,1)\)

عندما \(a=b=c=1\)، يكون

$$p=3,\qquad s=\frac{3}{2},\qquad x=y=z=1.$$

ومن ثم

$$r^2=\frac{xyz}{4p}=\frac{1}{12}.$$

وجميع الزوايا تساوي \(\pi/3\)، لذلك

$$\sin\left(\frac{A}{2}\right)=\sin\left(\frac{\pi}{6}\right)=\frac{1}{2},\qquad q_A=q_B=\frac{1-\frac12}{1+\frac12}=\frac13.$$

إذن

$$F(1,1,1)=\pi\cdot\frac{1}{12}\left(1+\frac{1}{9}+\max\left\{\frac{1}{9},\frac{1}{81}\right\}\right)=\pi\cdot\frac{1}{12}\left(1+\frac{1}{9}+\frac{1}{9}\right)=\frac{11\pi}{108}.$$

عدديًا نحصل على

$$\frac{11\pi}{108}\approx 0.31998.$$

وبما أن \(T_2\) لا يحتوي إلا هذا المثلث، فإن \(S(2)=0.31998\)، وهو بالضبط مقدار التحقق.

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

تنفيذات C++ وPython وJava كلها تقيم الصيغة نفسها. فهي تعدّد جميع المثلثات المسموح بها بترتيب \(a\) ثم \(b\) ثم جميع قيم \(c\) التي تحقق

$$b\le c\le a+b-1.$$

لكل مثلث، يحسب التنفيذ \(p\) و\(x\) و\(y\) و\(z\)، ثم يستخرج \(r^2=xyz/(4p)\)، وبعد ذلك يحسب كميات نصف الزاوية المطلوبة لـ \(A\) و\(B\)، ويبني \(q_A\) و\(q_B\)، ثم يضيف

$$\pi r^2\left(1+q_A^2+\max\{q_B^2,q_A^4\}\right)$$

إلى مجموع جارٍ ويزيد عداد المثلثات.

في النهاية تكون الإجابة هي المجموع الكلي مقسومًا على عدد المثلثات. تنفيذ Java يستخدم جمعًا تعويضيًا لتقليل ضياع الدقة في الأعداد العائمة، بينما يستخدم حساب C++ دقة موسعة. أما تنفيذ Python فيعتمد على الروتين العددي المترجم نفسه، ولذلك تشترك التنفيذات الثلاثة في الهندسة نفسها وفي نقاط التحقق نفسها.

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

عدد المثلثات المسموح بها هو

$$|T_n|=\sum_{a=1}^{\lfloor n/2\rfloor}\sum_{b=a}^{n-a} a,$$

وذلك لأن \(c\) عند تثبيت \(a\) و\(b\) يتحرك من \(b\) حتى \(a+b-1\)، أي يملك بالضبط \(a\) اختيارات. رتبة هذا العدد هي \(\Theta(n^3)\)، وبالتالي فالزمن الكلي أيضًا \(\Theta(n^3)\).

العمل داخل كل مثلث ثابت: عدد قليل من العمليات الحسابية، وبعض الجذور التربيعية، ومقارنة واحدة لأخذ القيمة العظمى. الذاكرة \(O(1)\)، لأن التنفيذ يحتفظ فقط بمجموع جارٍ، وعدّاد، وبضعة متغيرات عائمة مؤقتة.

هوامش ومراجع

  1. صفحة المسألة: https://projecteuler.net/problem=476
  2. الدائرة الداخلية والدوائر الخارجية: Wikipedia — Incircle and excircles of a triangle
  3. صيغة هيرون: Wikipedia — Heron's formula
  4. صيغ نصف الزاوية: Wikipedia — Half-angle formulae