Hier ist ein täuschend herausforderndes Geometrie-Puzzle für Sie!
Finden Sie bei einem Kreis A
und n
anderen Kreisen B[n]
die Gesamtfläche, die in A
diesem Kreis enthalten ist, und nicht in einem Kreis von B
.
Ihr Code sollte so kurz wie möglich sein.
Eingang
Ihre Eingabe sollte die folgenden Informationen enthalten:
- Eine Gleitkommazahl zur Darstellung des Kreisradius
A
. - Eine Liste von Gleitkommazahlen zur Darstellung der Radien von Kreisen in
B
. - Eine Liste der Zentren der Kreise in
B
. Ihr Programm kann die Zentren entweder in Polarkoordinaten oder in kartesischen Koordinaten erwarten. - Optional können Sie die Anzahl
n
der Kreise in B erhalten. Diese Eingabe ist nicht erforderlich.
Es wird angenommen, dass der Mittelpunkt des Kreises A
der Ursprung, das heißt der Punkt ist (0, 0)
.
Es wird garantiert, dass keine zwei Kreise in B
identisch sind, aber es wird nicht garantiert, dass: alle B
Schnittkreise A
, alle Zentren von B
außerhalb A
sind oder keine zwei Kreise in B
einander schneiden. Stellen Sie sicher, dass Ihre Lösung verschiedene Edge Cases verarbeiten kann.
Sie können Eingaben in beliebiger Reihenfolge und in Form von Texteingaben (über stdin oder die entsprechende Sprache), Funktionsparametern oder Befehlszeilenargumenten erhalten.
Wenn Sie Texteingaben erhalten möchten, sollten zwischen den Eingaben ein oder zwei druckbare ASCII-Trennzeichen stehen.
Ausgabe
Ihr Programm oder Ihre Funktion sollte eine einzelne Gleitkommazahl ausgeben, die die Gesamtfläche von A
in keinem der Kreise von repräsentiert B
. Ihre Antworten sollten für alle Testfälle auf mindestens drei signifikante Zahlen genau sein.
Es gelten die allgemeinen Code-Golf- Regeln.
Ihre Lösung sollte sich nicht auf Stichprobenpunkte innerhalb der Kreise stützen, um eine Fläche zu bestimmen.
Integrierte Funktionen, mit denen Schnittpunkte von Kreisen automatisch lokalisiert, Bereiche innerhalb von Schnittpunkten von Kreisen gefunden oder dieses Problem sofort behoben werden können, sind nicht zulässig.
Testfälle
In jedem Bild ist der Kreis A
blau umrandet, die Kreise B
grün umrandet und schwarz ausgefüllt. Der Bereich, der zurückgegeben werden soll, ist rot ausgefüllt.
(Besonderer Dank geht an Rainer P. für die Prüfung meiner Lösungen)
Testfall 1:
A = {x: 0, y: 0, rad: 50}
B[0] = {x: 0, y: 0, rad: 100}
Result: 0.00
Testfall 2:
A = {x: 0, y: 0, rad: 100.000000}
B[0] = {x: 100.000000, y: 0.000000, rad: 50.000000}
B[1] = {x: 30.901699, y: -95.105652, rad: 50.000000}
B[2] = {x: -80.901699, y: -58.778525, rad: 50.000000}
B[3] = {x: -80.901699, y: 58.778525, rad: 50.000000}
B[4] = {x: 30.901699, y: 95.105652, rad: 50.000000}
Result: 1.3878e+04
Testfall 3:
A = {x: 0, y: 0, rad: 138}
B[0] = {x: 100, y: 0, rad: 100}
B[1] = {x: -50, y: -86, rad: 100}
B[2] = {x: -93, y: 135, rad: 50}
Result: 1.8969e+04
Testfall 4:
A = {x: 0, y: 0, rad: 121.593585}
B[0] = {x: 81.000000, y: 107.000000, rad: 59.841457}
B[1] = {x: -152.000000, y: -147.000000, rad: 50.000000}
B[2] = {x: 43.000000, y: -127.000000, rad: 105.118980}
B[3] = {x: 0.000000, y: -72.000000, rad: 57.870545}
B[4] = {x: -97.000000, y: -81.000000, rad: 98.488578}
B[5] = {x: -72.000000, y: 116.000000, rad: 66.468037}
B[6] = {x: 2.000000, y: 51.000000, rad: 50.000000}
Result: 1.1264e+04
Testfall 5:
A = {x: 0, y: 0, rad: 121.605921}
B[0] = {x: 0.000000, y: -293.000000, rad: 250.000000}
B[1] = {x: 0.000000, y: -56.000000, rad: 78.230429}
B[2] = {x: 0.000000, y: -102.000000, rad: 100.000000}
Result: 2.6742e+04
Vorgeschlagene Literatur:
Fewell, MP "Bereich der gemeinsamen Überlappung von drei Kreisen." Okt. 2006. Web. http://dspace.dsto.defence.gov.au/dspace/bitstream/1947/4551/4/DSTO-TN-0722.PR.pdf .
quelle
B
einen anderen enthält. Könnte es wert sein, das hinzuzufügen.1.8970e+04
.B[0] - A intersection: 20653.659515
,B[1] - A intersection: 20757.824115
,B[1] - B[0] intersection: 1841.847766
,B[2] - A intersection: 1289.164541
, das ergibt18969.69009
als die Antwort.Antworten:
Python 2, 631 Bytes
Die vorangestellten Zeilenumbrüche dienen dem
\
einfachen Lesen und werden in der Partitur nicht mitgezählt.Liest die Eingabe über STDIN als Liste von
(center, radius)
Paaren, wobeicenter
das Formular eine komplexe Zahl enthältX+Yj
. Der erste Kreis in der Liste A (dessen Zentrums muss nicht am Ursprung sein), und der Rest der Liste ist B . Gibt das Ergebnis an STDOUT aus.Beispiel
Erläuterung
Dies ist eine (längere und viel hässlichere: P) Variante meiner Lösung für Martin Büttners Area of a Self-Intersecting Polygon Challenge. Es wird der gleiche Trick angewendet, bei dem das Problem in ausreichend kleine Teile zerlegt wird, für die es leichter zu handhaben ist.
Wir finden die Schnittpunkte zwischen allen Kreispaaren (unter Berücksichtigung von A und den Kreisen in B ) und ziehen jeweils eine vertikale Linie durch diese. Zusätzlich übergeben wir alle vertikalen Linien, die einen der Kreise berühren. Wir werfen alle Linien weg, die A nicht schneiden , so dass alle verbleibenden Linien zwischen der linken und rechten Tangente von A liegen .
Wir suchen nach dem Schnittbereich von A und der Vereinigung der Kreise in B - dem dunkelroten Bereich in der Abbildung oben. Dies ist der Bereich, den wir von A subtrahieren müssen , um das Ergebnis zu erhalten.
Zwischen jedem Paar aufeinanderfolgender vertikaler Linien kann dieser Bereich in eine Reihe vertikaler Trapezoide (oder Dreiecke oder Liniensegmente, als Sonderfälle von Trapezoiden) mit einem "überschüssigen" Bogensegment neben jedem Schenkel unterteilt werden. Die Tatsache, dass wir so viele vertikale Linien wie wir passieren, garantiert, dass der begrenzte Bereich tatsächlich nicht komplizierter ist, da es sonst einen zusätzlichen Schnittpunkt und damit eine zusätzliche vertikale Linie zwischen den beiden Linien in geben müsste Frage.
Um diese Trapezoide und Bogensegmente für jedes Paar aufeinanderfolgender vertikaler Linien zu finden, finden wir die Bogensegmente jedes der Kreise, die ordnungsgemäß zwischen diesen beiden Linien liegen (natürlich haben einige Kreise möglicherweise kein Bogensegment zwischen einem bestimmten Linienpaar .) In der folgenden Abbildung sind dies die sechs (hellen und dunklen) gelben Bogensegmente unter Berücksichtigung der beiden roten vertikalen Linien. Beachten Sie, dass ein Kreis, wenn er ein Bogensegment zwischen den beiden Linien hat, beide Linien schneidet, da wir alle vertikalen Linien tangential zu den Kreisen übergeben, was den Rest des Algorithmus vereinfacht.
Nicht alle diese Bögen sind relevant. Wir interessieren uns nur für diejenigen, die an der Grenze zwischen A und der Vereinigung von B liegen . Um diese zu finden, sortieren wir die Bögen von oben nach unten (beachten Sie, dass sich die Bögen möglicherweise nicht richtig schneiden, da dies die Existenz einer weiteren vertikalen Linie zwischen den beiden, die wir betrachten, implizieren würde, und es daher sinnvoll ist, zu sprechen über oder unter einem beliebigen Bogen.)
Wir durchlaufen die Bögen der Reihe nach und zählen dabei die Anzahl der B- Kreise, in denen wir uns gerade befinden, n . Wenn sich n von 0 auf 1 ändert, während wir in A sind , oder wenn wir am oberen Bogen von A sind, während n ungleich Null ist, entspricht der aktuelle Bogen einem Bein eines Trapezes. Wenn n von 1 nach 0 wechselt, während wir in A sind , oder wenn wir im unteren Bogen von A sind, während nungleich Null ist, dann entspricht der Strombogen dem anderen Schenkel desselben Trapezes. Sobald wir ein solches Bogenpaar gefunden haben (die beiden hellgelben Bögen in der obigen Abbildung), berechnen wir die Fläche des entsprechenden Trapezes und der beiden Bogensegmente und addieren sie zur Gesamtfläche, die von A subtrahiert werden soll .
Die Berechnung der Fläche von A sowie der Flächen der Trapezoide ist relativ einfach. Die Fläche jedes Bogensegments ist die Fläche des entsprechenden Kreissektors abzüglich der Fläche des Dreiecks, dessen Eckpunkte die beiden Endpunkte des Bogensegments sind, und des Mittelpunkts des entsprechenden Kreises.
quelle