Considérons un polygone potentiellement auto-intersecté, défini par une liste de sommets dans un espace 2D. Par exemple
{{0, 0}, {5, 0}, {5, 4}, {1, 4}, {1, 2}, {3, 2}, {3, 3}, {2, 3}, {2, 1}, {4, 1}, {4, 5}, {0, 5}}
Il existe plusieurs façons de définir l'aire d'un tel polygone, mais la plus intéressante est la règle pair-impair. En prenant n'importe quel point dans l'avion, tracez une ligne du point vers l'infini (dans n'importe quelle direction). Si cette ligne traverse le polygone un nombre impair de fois, le point fait partie de la zone du polygone, s'il traverse le polygone un nombre pair de fois, le point ne fait pas partie du polygone. Pour l'exemple de polygone ci-dessus, voici à la fois son contour ainsi que sa zone paire-impaire:
Le polygone ne sera en général pas orthogonal. Je n'ai choisi qu'un exemple aussi simple pour faciliter le comptage de la zone.
La zone de cet exemple est 17
(pas 24
ou 33
comme d'autres définitions ou zones pourraient donner).
Notez que sous cette définition, l'aire du polygone est indépendante de son ordre d'enroulement.
Le défi
Étant donné une liste de sommets avec des coordonnées entières définissant un polygone, déterminez son aire sous la règle pair-impair.
Vous pouvez écrire une fonction ou un programme, en saisissant des données via STDIN ou l'alternative la plus proche, l'argument de ligne de commande ou l'argument de fonction et renvoyer le résultat ou l'imprimer dans STDOUT ou l'alternative la plus proche.
Vous pouvez prendre des entrées dans n'importe quel format de liste ou de chaîne pratique, tant qu'il n'est pas prétraité.
Le résultat doit être soit un nombre à virgule flottante, précis à 6 chiffres significatifs (décimaux), soit un résultat rationnel dont la représentation à virgule flottante est précise à 6 chiffres significatifs. (Si vous produisez des résultats rationnels, ils seront probablement exacts, mais je ne peux pas l'exiger, car je n'ai pas de résultats exacts pour référence.)
Vous devez être en mesure de résoudre chacun des cas de test ci-dessous dans les 10 secondes sur une machine de bureau raisonnable. (Il y a une certaine marge de manœuvre dans cette règle, alors utilisez votre meilleur jugement. Si cela prend 20 secondes sur mon ordinateur portable, je vous donnerai le bénéfice du doute, si cela prend une minute, je ne le ferai pas.) Je pense que cette limite devrait être très généreux, mais il est censé exclure les approches où vous discrétisez simplement le polygone sur une grille et un décompte suffisamment fins, ou utilisez des approches probabilistes comme Monte Carlo. Soyez un bon sportif et n'essayez pas d'optimiser ces approches de manière à pouvoir respecter le délai de toute façon. ;)
Vous ne devez utiliser aucune fonction existante directement liée aux polygones.
Il s'agit du code golf, donc la soumission la plus courte (en octets) l'emporte.
Hypothèses
- Toutes les coordonnées sont des nombres entiers dans la gamme
0 ≤ x ≤ 100
,0 ≤ y ≤ 100
. - Il y aura au moins
3
et au plus des50
sommets. - Il n'y aura pas de sommets répétés. Aucun sommet ne se trouvera non plus sur un autre bord. (Il peut cependant y avoir des points colinéaires dans la liste.)
Cas de test
{{0, 0}, {5, 0}, {5, 4}, {1, 4}, {1, 2}, {3, 2}, {3, 3}, {2, 3}, {2, 1}, {4, 1}, {4, 5}, {0, 5}}
17.0000
{{22, 87}, {6, 3}, {98, 77}, {20, 56}, {96, 52}, {79, 34}, {46, 78}, {52, 73}, {81, 85}, {90, 43}}
2788.39
{{90, 43}, {81, 85}, {52, 73}, {46, 78}, {79, 34}, {96, 52}, {20, 56}, {98, 77}, {6, 3}, {22, 87}}
2788.39
{{70, 33}, {53, 89}, {76, 35}, {14, 56}, {14, 47}, {59, 49}, {12, 32}, {22, 66}, {85, 2}, {2, 81},
{61, 39}, {1, 49}, {91, 62}, {67, 7}, {19, 55}, {47, 44}, {8, 24}, {46, 18}, {63, 64}, {23, 30}}
2037.98
{{42, 65}, {14, 59}, {97, 10}, {13, 1}, {2, 8}, {88, 80}, {24, 36}, {95, 94}, {18, 9}, {66, 64},
{91, 5}, {99, 25}, {6, 66}, {48, 55}, {83, 54}, {15, 65}, {10, 60}, {35, 86}, {44, 19}, {48, 43},
{47, 86}, {29, 5}, {15, 45}, {75, 41}, {9, 9}, {23, 100}, {22, 82}, {34, 21}, {7, 34}, {54, 83}}
3382.46
{{68, 35}, {43, 63}, {66, 98}, {60, 56}, {57, 44}, {90, 52}, {36, 26}, {23, 55}, {66, 1}, {25, 6},
{84, 65}, {38, 16}, {47, 31}, {44, 90}, {2, 30}, {87, 40}, {19, 51}, {75, 5}, {31, 94}, {85, 56},
{95, 81}, {79, 80}, {82, 45}, {95, 10}, {27, 15}, {18, 70}, {24, 6}, {12, 73}, {10, 31}, {4, 29},
{79, 93}, {45, 85}, {12, 10}, {89, 70}, {46, 5}, {56, 67}, {58, 59}, {92, 19}, {83, 49}, {22,77}}
3337.62
{{15, 22}, {71, 65}, {12, 35}, {30, 92}, {12, 92}, {97, 31}, {4, 32}, {39, 43}, {11, 40},
{20, 15}, {71, 100}, {84, 76}, {51, 98}, {35, 94}, {46, 54}, {89, 49}, {28, 35}, {65, 42},
{31, 41}, {48, 34}, {57, 46}, {14, 20}, {45, 28}, {82, 65}, {88, 78}, {55, 30}, {30, 27},
{26, 47}, {51, 93}, {9, 95}, {56, 82}, {86, 56}, {46, 28}, {62, 70}, {98, 10}, {3, 39},
{11, 34}, {17, 64}, {36, 42}, {52, 100}, {38, 11}, {83, 14}, {5, 17}, {72, 70}, {3, 97},
{8, 94}, {64, 60}, {47, 25}, {99, 26}, {99, 69}}
3514.46
upath
et les lineto
sons comme si vous prétraitez réellement l'entrée. C'est-à-dire que vous ne prenez pas une liste de coordonnées mais un véritable polygone.
CrossingPolygon
.
upath
opérateur. (Il s'agit en fait d'une conversion 1: 1 extrêmement simple entre les séparateurs. Devient}, {
justelineto
, et la virgule entre les x et y est supprimée, et les accolades d'ouverture et de fermeture sont remplacées par un en-tête et un pied de page statiques ...)