Đếm số cạnh trên đa giác


18

Đếm số cạnh trên đa giác

Robot đếm đa giác đã quyết định đi khắp thế giới mà không nói cho ai biết trước đó, nhưng điều quan trọng là quá trình đếm đa giác không bị dừng quá lâu. Vì vậy, bạn có nhiệm vụ sau: Đưa ra hình ảnh đen trắng của đa giác, chương trình / functoin của bạn sẽ trả về số cạnh.

Chương trình sẽ được đưa đến một máy tính thẻ đục lỗ cũ, và vì thẻ đục lỗ hiện nay rất đắt tiền, tốt nhất bạn nên cố gắng làm cho chương trình của mình càng ngắn càng tốt.

Các cạnh dài ít nhất 10 pixel và các góc được tạo bởi hai cạnh phụ ít nhất là 10 ° nhưng không quá 170 ° (hoặc lớn hơn 190 °). Đa giác được chứa hoàn toàn trong hình ảnh và đa giác cũng như phần bổ sung của nó được kết nối (không có đảo bị cô lập) nên đầu vào này sẽ không hợp lệ:

nhập mô tả hình ảnh ở đây

Chấm điểm

Đây là codegolf, có nghĩa là lần gửi ngắn nhất tính bằng byte, bài nộp của bạn phải tìm đúng số cạnh cho mỗi trường hợp kiểm tra. (Và việc gửi cũng nên hoạt động cho các trường hợp khác, tối ưu hóa cho những trường hợp thử nghiệm đó là không được phép.)

Nếu bạn muốn gửi một giải pháp không tìm thấy số chính xác mỗi lần, bạn cũng có thể gửi giải pháp đó, nhưng nó sẽ được xếp sau tất cả các bài nộp hoạt động tốt hơn.

Vui lòng bao gồm tổng số trong tiêu đề trình của bạn. (Tổng lỗi tổng số chênh lệch tuyệt đối giữa số cạnh thực và mỗi đầu ra).

Các trường hợp thử nghiệm

n = 10

nhập mô tả hình ảnh ở đâynhập mô tả hình ảnh ở đây

n = 36

nhập mô tả hình ảnh ở đâynhập mô tả hình ảnh ở đây

n = 7

nhập mô tả hình ảnh ở đâynhập mô tả hình ảnh ở đây

n = 5

nhập mô tả hình ảnh ở đâynhập mô tả hình ảnh ở đây

Đây không phải là một trường hợp thử nghiệm, chỉ vì tò mò: bạn nhận được bao nhiêu cạnh cho đầu vào này?

nhập mô tả hình ảnh ở đây


Tôi thấy nhiều góc độ trong các trường hợp thử nghiệm của bạn lớn hơn 170 °. Ví dụ: tất cả các góc "không điểm" (những góc gần trung tâm hơn) trong ngôi sao của bạn.
Doorknob

@Doorknob Đó là góc nhỏ hơn nên nhỏ hơn 170 °.
lirtosiast

Có, nhưng chúng lại lớn hơn 190 °. Điểm hạn chế này là loại bỏ các ví dụ trong đó hai bên không thể phân biệt được.
flawr

2
Màu nào là nội thất của đa giác?
frageum

1
Chương trình sẽ được đưa vào một máy tính thẻ đục lỗ cũ và ngày nay, thẻ đục lỗ rất đắt tiền, tốt nhất bạn nên cố gắng làm cho chương trình của mình càng ngắn càng tốt :-)
Luis Mendo

Câu trả lời:


12

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 vvà "đ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; dban đầ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ủaohoặ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 dhướ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 pnằ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 pdtheo đó trước khi tiếp tục.

Mỗi lần khoảng cách giữa pvà điểm kiểm tra cuối cùng qlớ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 qhay 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 qpdọ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.

n = 10 n = 36 n = 7 n = 5 Vòng tròn


Cảm ơn bạn đã giải thích chi tiết này! Tôi thích minh họa của bạn!
flawr

Nếu có một cạnh về phía đông o, thì đầu kia sẽ còn xa hơn nữa từ nguồn gốc chứ?
aditsu

1
@aditsu Tôi nghĩ thuật ngữ này có thể hơi khó hiểu ở đây. Chúng ta nói về các cạnh của đa giác, theo nghĩa hình học và các cạnh của (bộ pixel bao gồm) đa giác, như một đồ họa raster. olà pixel phía trước xa nhất so với điểm gốc, do đó, pixel ở phía đông của nó phải là pixel nền, do đó chúng tôi nói rằng có một cạnh ở phía đông o.
Ell
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.