Considera un poligono potenzialmente autointersecante, definito da un elenco di vertici nello spazio 2D. Per esempio
{{0, 0}, {5, 0}, {5, 4}, {1, 4}, {1, 2}, {3, 2}, {3, 3}, {2, 3}, {2, 1}, {4, 1}, {4, 5}, {0, 5}}
Esistono diversi modi per definire l'area di tale poligono, ma la più interessante è la regola pari-dispari. Prendendo qualsiasi punto nel piano, traccia una linea dal punto verso l'infinito (in qualsiasi direzione). Se quella linea attraversa il poligono un numero dispari di volte, il punto fa parte dell'area del poligono, se attraversa il poligono un numero pari di volte, il punto non fa parte del poligono. Per il poligono di esempio sopra, ecco sia il suo contorno che la sua area pari:
Il poligono non sarà generalmente ortogonale. Ho scelto solo un esempio così semplice per rendere più semplice il conteggio dell'area.
L'area di questo esempio è 17
(no 24
o 33
come potrebbero dare altre definizioni o area).
Si noti che in base a questa definizione l'area del poligono è indipendente dal suo ordine di avvolgimento.
La sfida
Dato un elenco di vertici con coordinate intere che definiscono un poligono, determinane l'area sotto la regola pari-dispari.
È possibile scrivere una funzione o un programma, prendendo l'input tramite STDIN o l'alternativa più vicina, l'argomento della riga di comando o l'argomento della funzione e restituire il risultato o stamparlo su STDOUT o l'alternativa più vicina.
È possibile accettare input in qualsiasi elenco o formato stringa, purché non sia preelaborato.
Il risultato dovrebbe essere un numero in virgola mobile, accurato su 6 cifre (decimali) significative, oppure un risultato razionale la cui rappresentazione in virgola mobile è accurata su 6 cifre significative. (Se produci risultati razionali, saranno probabilmente esatti, ma non posso richiederlo, poiché non ho risultati esatti per riferimento.)
Devi essere in grado di risolvere ciascuno dei casi di test di seguito entro 10 secondi su una macchina desktop ragionevole. (C'è qualche margine di manovra in questa regola, quindi usa il tuo miglior giudizio. Se ci vorranno 20 secondi sul mio laptop, ti darò il beneficio del dubbio, se ci vorrà un minuto, non lo farò.) Penso che questo limite dovrebbe essere molto generoso, ma si suppone che escluda approcci in cui si discretizza il poligono su una griglia sufficientemente sottile e si conta, oppure si utilizzano approcci probabilistici come Monte Carlo. Sii un buon sportivo e non cercare di ottimizzare questi approcci in modo tale da poter comunque rispettare il limite di tempo. ;)
Non è necessario utilizzare alcuna funzione esistente direttamente correlata ai poligoni.
Questo è il golf del codice, quindi vince l'invio più breve (in byte).
ipotesi
- Tutte le coordinate sono numeri interi nella gamma
0 ≤ x ≤ 100
,0 ≤ y ≤ 100
. - Ci saranno almeno
3
e al massimo50
vertici. - Non ci saranno vertici ripetuti. Né i vertici si trovano su un altro bordo. (Tuttavia, potrebbero esserci punti collineari nell'elenco).
Casi 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
e lineto
sembra che tu stia effettivamente preelaborando l'input. Cioè non stai prendendo un elenco di coordinate ma un vero poligono.
CrossingPolygon
.
upath
operatore. (In realtà è una conversione 1: 1 estremamente semplice tra i separatori.}, {
Diventa sololineto
, e la virgola tra xey viene rimossa e le parentesi graffe di apertura e chiusura vengono sostituite con un'intestazione e un piè di pagina statici ...)