Python 2 + PIL, nessun errore, 313 307 byte
from Image import*
I=open(sys.argv[1])
w,h=I.size;D=I.getdata()
B={i%w+i/w*1j for i in range(w*h)if D[i]!=D[0]}
n=d=1;o=v=q=p=max(B,key=abs)
while p-w:
p+=d*1j;e=2*({p}<B)+({p+d}<B)
if e!=2:e%=2;d*=1j-e*2j;p-=d/1j**e
if abs(p-q)>5:
t=(q-v)*(p-q).conjugate();q=p;w=o
if.98*abs(t)>t.real:n+=1;v=p
print n
Prende il nome di un file immagine dalla riga di comando e stampa il risultato su STDOUT.
Fornisce il risultato corretto per tutti i test e n = 28 per il cerchio.
Spiegazione
L'algoritmo funziona camminando lungo il perimetro del poligono e contando il numero di vertici rilevati (rilevati come cambiamenti di direzione). Iniziamo dal pixel più lontano dall'origine, o
che è garantito per essere un vertice, e quindi, per essere adiacente ad un bordo (cioè un confine tra un pixel di primo piano e un pixel di sfondo). Teniamo traccia della nostra posizione, p
il vertice più recente v
e il "checkpoint" più recente q
, che inizialmente sono tutti uguali o
. Teniamo anche traccia della direzione del bordo d
, rispetto al pixel corrente; d
inizialmente punta ad est, che è una direzione sicura, poiché sappiamo che c'è un bordo ad est dio
, altrimenti non sarebbe più lontano dall'origine. Ci muoviamo lungo il bordo, in una direzione perpendicolare a d
, tale che d
punta alla nostra sinistra, cioè in senso orario. Ogni volta che "cadiamo dal bordo", cioè in qualsiasi situazione p
al di fuori del poligono o in cui il pixel alla nostra sinistra (cioè nella direzione di d
) si trova all'interno del poligono, ci adeguiamo p
e di d
conseguenza prima di riprendere.
Ogni volta che la distanza tra p
e l'ultimo punto di controllo, q
diventa maggiore di 5, proviamo a determinare se abbiamo superato un vertice tra q
e p
: confrontiamo l'angolo tra vq
(cioè il vettore da v
a q
), che è la direzione generale del lato del poligono che stavamo percorrendo quando abbiamo raggiunto l'ultimo checkpoint e qp
lo spostamento tra l'ultimo checkpoint e la posizione corrente. Se l'angolo è maggiore di circa 10 °, concludiamo che stiamo camminando lungo un lato diverso del poligono, aumentiamo il conteggio dei vertici e impostiamo v
il vertice corrente su p
. Ad ogni checkpoint, indipendentemente dal fatto che abbiamo rilevato un vertice o meno, aggiorniamo q
, l'ultimo checkpoint, ap
. Continuiamo in questo modo fino a quando non arriviamo al o
punto di partenza e restituiamo il numero di vertici trovati (si noti che il conteggio dei vertici è inizialmente 1, poiché il punto di partenza o
, è esso stesso un vertice).
Le immagini seguenti mostrano i vertici rilevati. Si noti che prendendo p
, la posizione corrente in ciascun checkpoint, poiché la posizione del nuovo vertice non è ottimale, poiché il vertice reale è probabilmente da qualche parte tra l'ultimo checkpoint q
e p
, lungo il perimetro. Come puoi vedere, tutti i vertici diversi dal primo (generalmente il vertice in basso a destra) sono un po 'spenti. La correzione di questo costerebbe più byte, ma sembra funzionare abbastanza bene così com'è. Detto questo, è un po 'difficile non esagerare con solo quattro casi di test.