Python 2 + PIL, bez błędów, 313 307 bajtów
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
Pobiera nazwę pliku obrazu w wierszu polecenia i drukuje wynik do STDOUT.
Podaje poprawny wynik dla wszystkich testów, a n = 28 dla koła.
Wyjaśnienie
Algorytm działa, idąc wzdłuż obwodu wielokąta i licząc liczbę napotkanych wierzchołków (wykrytych jako zmiany kierunku). Zaczynamy od piksela najbardziej oddalonego od początku, o
który z pewnością jest wierzchołkiem, a zatem przylega do krawędzi (tj. Granicy między pikselem pierwszego planu i pikselem tła). Śledzimy naszą pozycję, p
najnowszy wierzchołek v
i najnowszy „punkt kontrolny”, q
z których wszystkie są początkowo równe o
. Śledzimy również kierunek krawędzi d
względem bieżącego piksela; d
początkowo wskazuje wschód, co jest bezpiecznym kierunkiem, ponieważ wiemy, że jest krawędź na wschód odo
, inaczej nie byłoby to najdalsze od pochodzenia. Poruszamy się wzdłuż krawędzi, w kierunku prostopadłym do punktów po naszej lewej stronie, tj. W kierunku zgodnym z ruchem wskazówek zegara. Ilekroć „spadamy z krawędzi”, tj. W każdej sytuacji, w której znajduje się poza wielokątem lub gdy piksel po naszej lewej stronie (tj. W kierunku ) znajduje się wewnątrz wielokąta, dostosowujemy i odpowiednio przed wznowieniem.d
takiego, któryd
p
d
p
d
Za każdym razem, gdy odległość między p
ostatnim punktem kontrolnym, a q
staje się większa niż 5, staramy się ustalić, czy minęliśmy wierzchołek między q
i p
: Porównujemy kąt między vq
(tj. Wektorem od v
do q
), który jest ogólnym kierunkiem bok wieloboku, którym szliśmy, gdy dotarliśmy do ostatniego punktu kontrolnego, oraz qp
przesunięcie między ostatnim punktem kontrolnym a bieżącą pozycją. Jeśli kąt jest większy niż około 10 °, dochodzimy do wniosku, że idziemy wzdłuż innej strony wielokąta, zwiększamy liczbę wierzchołków i ustawiamy v
bieżący wierzchołek na p
. W każdym punkcie kontrolnym, niezależnie od tego, czy wykryliśmy wierzchołek, czy nie, aktualizujemyq
ostatni punkt kontrolny dop
. Kontynuujemy w ten sposób, aż wrócimy o
do punktu początkowego i zwrócimy liczbę znalezionych wierzchołków (zauważ, że liczba wierzchołków wynosi początkowo 1, ponieważ punktem początkowym o
jest sam wierzchołek).
Poniższe obrazy pokazują wykryte wierzchołki. Zauważ, że biorąc p
, bieżąca pozycja w każdym punkcie kontrolnym, ponieważ pozycja nowego wierzchołka nie jest optymalna, ponieważ prawdziwy wierzchołek jest prawdopodobnie gdzieś pomiędzy ostatnim punktem kontrolnym q
i p
wzdłuż obwodu. Jak widać, wszystkie wierzchołki inne niż pierwszy (ogólnie prawy dolny wierzchołek) są nieco oddalone. Naprawienie tego kosztowałoby więcej bajtów, ale wydaje się, że działa wystarczająco dobrze, jak jest. Biorąc to pod uwagę, trudno jest nie nadużywać tylko czterech przypadków testowych.