Voici un puzzle de géométrie trompeusement difficile pour vous!
Étant donné un cercle A
et d' n
autres cercles B[n]
, trouvez l'aire totale contenue à l'intérieur A
qui ne se trouve dans aucun cercle de B
.
Votre code doit être aussi court que possible.
Contribution
Votre entrée doit contenir les informations suivantes:
- Un nombre à virgule flottante pour représenter le rayon du cercle
A
. - Une liste de nombres à virgule flottante pour représenter les rayons des cercles
B
. - Une liste des centres de cercles dans
B
. Votre programme peut s'attendre à ce que les centres soient en coordonnées polaires ou cartésiennes. - Facultativement, vous pouvez recevoir le nombre
n
de cercles en B. Cette entrée n'est pas requise.
Il faut supposer que le centre du cercle A
est l'origine, c'est-à-dire le point (0, 0)
.
Il est garanti qu'il n'y a pas deux cercles dans B
identiques, mais il n'est pas garanti que: tous les cercles d' B
intersection A
, tous les centres de B
sont à l'extérieur A
, ou pas deux cercles en B
intersection. Assurez-vous que votre solution peut gérer divers cas de bord.
Vous pouvez recevoir des entrées dans n'importe quel ordre et sous forme de saisie de texte (via stdin ou l'équivalent de votre langue), des paramètres de fonction ou des arguments de ligne de commande.
Si vous choisissez de recevoir une entrée de texte, il doit y avoir des délimiteurs ASCII imprimables à un ou deux caractères entre les éléments d'entrée.
Production
Votre programme ou fonction doit générer un seul nombre à virgule flottante représentant la zone totale de A
pas dans aucun des cercles de B
. Vos réponses doivent être précises à au moins trois chiffres significatifs pour tous les cas de test.
Les règles générales du code-golf s'appliquent.
Votre solution ne doit pas s'appuyer sur des points d'échantillonnage dans les cercles pour déterminer une zone.
Les éléments intégrés qui localisent automatiquement les intersections de cercles, trouvent des zones dans les intersections de cercles ou résolvent immédiatement ce problème sont interdits.
Cas de test
Dans chaque image, le cercle A
est délimité en bleu, avec des cercles B
délimités en vert et noir rempli. La zone à retourner est remplie en rouge.
(Un merci spécial à Rainer P. pour avoir vérifié mes solutions)
Cas de test 1:
A = {x: 0, y: 0, rad: 50}
B[0] = {x: 0, y: 0, rad: 100}
Result: 0.00
Cas de test 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
Cas de test 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
Cas de test 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
Cas de test 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
Lecture suggérée:
Fewell, MP "Zone de chevauchement commun de trois cercles." Octobre 2006. Web. http://dspace.dsto.defence.gov.au/dspace/bitstream/1947/4551/4/DSTO-TN-0722.PR.pdf .
la source
B
contient un autre. Cela pourrait valoir la peine d'ajouter cela.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
, ce qui donne18969.69009
comme réponse.Réponses:
Python 2, 631 octets
Les sauts de ligne précédés de
\
sont pour une lecture facile et ne sont pas comptés dans la partition.Lit l'entrée via STDIN sous la forme d'une liste de
(center, radius)
paires, oùcenter
est un nombre complexe dans le formulaireX+Yj
. Le premier cercle de la liste est un (dont le centre ne doit pas être à l'origine), et le reste de la liste est B . Imprime le résultat dans STDOUT.Exemple
Explication
Ceci est une variation (plus longue et beaucoup plus laide: P) de ma solution au défi de Martin Büttner, Zone d'un polygone auto-intersecté . Il utilise la même astuce pour décomposer le problème en morceaux assez petits, pour lesquels il devient plus gérable.
Nous trouvons les points d'intersection entre toutes les paires de cercles (en considérant à la fois A et les cercles en B ) et passons une ligne verticale à travers chacun d'eux. De plus, nous passons toutes les lignes verticales tangentes à l'un des cercles. Nous deux pas toutes les lignes qui ne sont pas Intersection A , de sorte que toutes les lignes restantes sont entre les tangentes gauche et à droite de A .
Nous recherchons l'aire de l'intersection de A et l'union des cercles en B - la zone rouge foncé dans l'illustration ci-dessus. C'est la zone que nous devons soustraire de A pour obtenir le résultat.
Entre chaque paire de lignes verticales consécutives, cette zone peut être décomposée en un ensemble de trapèzes verticaux (ou triangles ou segments de ligne, comme cas particuliers de trapèzes), avec un segment d'arc "en excès" à côté de chaque jambe. Le fait que nous passions autant de lignes verticales que nous garantissons que la zone délimitée n'est en effet pas plus compliquée que cela, car sinon il devrait y avoir un point d'intersection supplémentaire, et donc une ligne verticale supplémentaire, entre les deux lignes de question.
Pour trouver ces trapèzes et segments d'arc, pour chaque paire de lignes verticales consécutives, nous trouvons les segments d'arc de chacun des cercles qui se trouvent correctement entre ces deux lignes (bien sûr, certains cercles peuvent ne pas avoir de segment d'arc entre une paire de lignes donnée .) Dans l'illustration ci-dessous, ce sont les six segments d'arc jaune (lumineux et foncé), si l'on considère les deux lignes verticales rouges. Notez que, puisque nous passons toutes les lignes verticales tangentes aux cercles, si un cercle a un segment d'arc entre les deux lignes, il coupe nécessairement les deux lignes, ce qui simplifie le reste de l'algorithme.
Tous ces arcs ne sont pas pertinents; nous ne nous intéressons à ceux qui sont à la limite de l'intersection entre A et l'union de B . Pour les trouver, nous trions les arcs de haut en bas (notez que les arcs peuvent ne pas se croiser correctement, car cela impliquerait l'existence d'une autre ligne verticale entre les deux que nous considérons, et il est donc logique de parler à propos d'un arc arbitraire au-dessus ou en dessous de tout autre.)
Nous parcourons les arcs, dans l'ordre, tout en comptant le nombre de cercles B dans lesquels nous sommes actuellement, n . Si n passe de 0 à 1 alors que nous sommes à l'intérieur de A , ou si nous sommes à l'arc supérieur de A alors que n est non nul, alors l'arc actuel correspond à une jambe d'un trapèze. Si n passe de 1 à 0 alors que nous sommes à l'intérieur de A , ou si nous sommes à l'arc inférieur de A alors que nest différent de zéro, alors l'arc actuel correspond à l'autre jambe du même trapèze. Une fois que nous trouvons une telle paire d'arcs (les deux arcs jaune vif dans l'illustration ci - dessus), on calcule la zone du trapèze correspondant, et des deux segments d'arc, et l' ajouter à la surface totale à soustraire A .
Le calcul de l'aire de A , ainsi que des aires des trapèzes, est assez simple. L'aire de chaque segment d'arc est l'aire du secteur circulaire correspondant, moins l'aire du triangle dont les sommets sont les deux extrémités du segment d'arc et le centre du cercle correspondant.
la source