Python 2 + PIL, không có lỗi, 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
Lấy tên tệp hình ảnh trên dòng lệnh và in kết quả sang STDOUT.
Đưa ra kết quả chính xác cho tất cả các thử nghiệm và n = 28 cho vòng tròn.
Giải trình
Thuật toán hoạt động bằng cách đi dọc theo chu vi của đa giác và đếm số đỉnh gặp phải (được phát hiện là thay đổi theo hướng). Chúng ta bắt đầu ở điểm xa nhất so với điểm gốc, o
được đảm bảo là một đỉnh, và do đó, nằm liền kề với một cạnh (nghĩa là ranh giới giữa pixel phía trước và pixel nền). Chúng tôi theo dõi vị trí của chúng tôi, p
đỉnh gần đây nhất v
và "điểm kiểm tra" gần đây nhất q
, tất cả đều ban đầu bằng o
. Chúng tôi cũng theo dõi hướng của cạnh d
, liên quan đến pixel hiện tại; d
ban đầu chỉ về hướng đông, đó là một hướng an toàn, vì chúng ta biết có một cạnh về phía đông củao
hoặc nếu không nó sẽ không xa nguồn gốc. Chúng ta di chuyển dọc theo cạnh, theo hướng vuông góc với d
, sao cho d
hướng về bên trái của chúng ta, tức là theo chiều kim đồng hồ. Bất cứ khi nào chúng tôi "rơi ra khỏi rìa", tức là trong mọi tình huống p
nằm ngoài đa giác hoặc nơi pixel ở bên trái của chúng tôi (nghĩa là theo hướng d
) nằm trong đa giác, chúng tôi điều chỉnh p
và d
theo đó trước khi tiếp tục.
Mỗi lần khoảng cách giữa p
và điểm kiểm tra cuối cùng q
lớn hơn 5, chúng tôi cố gắng xác định xem chúng tôi có vượt qua một đỉnh giữa q
hay không p
: Chúng tôi so sánh góc giữa vq
(tức là vectơ từ v
đến q
), là hướng chung của bên của đa giác chúng ta đang đi dọc khi chúng ta đến điểm kiểm tra cuối cùng, và qp
, sự dịch chuyển giữa điểm kiểm tra cuối cùng và vị trí hiện tại. Nếu góc lớn hơn khoảng 10 °, chúng tôi kết luận rằng chúng ta đang đi dọc theo một phía khác của đa giác, tăng số lượng đỉnh và đặt v
, đỉnh hiện tại, thành p
. Tại mỗi điểm kiểm tra, bất kể chúng tôi có phát hiện ra một đỉnh hay không, chúng tôi cập nhật q
, điểm kiểm tra cuối cùng, đểp
. Chúng tôi tiếp tục theo cách này cho đến khi chúng tôi quay lại o
, điểm bắt đầu và trả về số đỉnh được tìm thấy (lưu ý rằng số đỉnh ban đầu là 1, vì điểm bắt đầu o
, chính nó là một đỉnh.)
Các hình ảnh dưới đây cho thấy các đỉnh được phát hiện. Lưu ý rằng việc lấy p
, vị trí hiện tại ở mỗi điểm kiểm tra, vì vị trí của đỉnh mới là không tối ưu, vì đỉnh thực sự có thể nằm ở đâu đó giữa điểm kiểm tra cuối cùng q
và p
dọc theo chu vi. Như bạn có thể thấy, tất cả các đỉnh khác với đỉnh đầu tiên (nói chung là đỉnh dưới cùng bên phải) có một chút tắt. Sửa lỗi này sẽ tốn nhiều byte hơn, nhưng dường như nó vẫn hoạt động đủ tốt. Điều đó đang được nói, thật khó để không vượt qua chỉ với bốn trường hợp thử nghiệm.