Tìm Hull Convex của một tập hợp các điểm 2D


20

Khi bạn đóng một bộ đinh vào một tấm gỗ và quấn một dải cao su xung quanh chúng, bạn sẽ có được một Convex Hull .

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

Nhiệm vụ của bạn, nếu bạn quyết định chấp nhận nó, là tìm Convex Hull của một tập hợp các điểm 2D nhất định.


Một số quy tắc:

  • Viết nó dưới dạng hàm, tọa độ danh sách của điểm (theo bất kỳ định dạng nào bạn muốn) là đối số
  • Đầu ra phải là danh sách các điểm trong thân lồi được liệt kê theo chiều kim đồng hồ hoặc ngược chiều kim đồng hồ, bắt đầu từ bất kỳ điểm nào trong số chúng
  • Danh sách đầu ra có thể ở bất kỳ định dạng hợp lý nào trong đó tọa độ của mỗi điểm có thể phân biệt rõ ràng. (Ví dụ: KHÔNG phải là một danh sách mờ {0.1, 1.3, 4, ...})
  • Nếu ba hoặc nhiều điểm trong một đoạn của thân lồi được căn chỉnh, chỉ nên giữ hai điểm cực trị trên đầu ra

Dữ liệu mẫu:

Mẫu 0

Đầu vào:

{{1, 1}, {2, 2}, {3, 3}, {1, 3}}

Đầu ra:

{{3, 3}, {1, 3}, {1, 1}}

Đồ họa toán học (Các số liệu chỉ mang tính minh họa)

Mẫu 1

Đầu vào:

{{4.4, 14}, {6.7, 15.25}, {6.9, 12.8}, {2.1, 11.1}, {9.5, 14.9}, 
 {13.2, 11.9}, {10.3, 12.3}, {6.8, 9.5}, {3.3, 7.7}, {0.6, 5.1}, {5.3, 2.4}, 
 {8.45, 4.7}, {11.5, 9.6}, {13.8, 7.3}, {12.9, 3.1}, {11, 1.1}}

Đầu ra:

{{13.8, 7.3}, {13.2, 11.9}, {9.5, 14.9}, {6.7, 15.25}, {4.4, 14}, 
 {2.1, 11.1}, {0.6, 5.1}, {5.3, 2.4}, {11, 1.1}, {12.9, 3.1}}

Đồ họa toán học

Mẫu 2

Đầu vào:

{{1, 0}, {1, 1}, {1, -1}, {0.68957, 0.283647}, {0.909487, 0.644276}, 
 {0.0361877, 0.803816}, {0.583004, 0.91555}, {-0.748169, 0.210483}, 
 {-0.553528, -0.967036}, {0.316709, -0.153861}, {-0.79267, 0.585945},
 {-0.700164, -0.750994}, {0.452273, -0.604434}, {-0.79134, -0.249902}, 
 {-0.594918, -0.397574}, {-0.547371, -0.434041}, {0.958132, -0.499614}, 
 {0.039941, 0.0990732}, {-0.891471, -0.464943}, {0.513187, -0.457062}, 
 {-0.930053, 0.60341}, {0.656995, 0.854205}}

Đầu ra:

{{1, -1}, {1, 1}, {0.583004, 0.91555}, {0.0361877, 0.803816}, 
 {-0.930053, 0.60341}, {-0.891471, -0.464943}, {-0.700164, -0.750994}, 
 {-0.553528, -0.967036}}

Đồ họa toán học

Luật golf tiêu chuẩn được áp dụng. Không có thư viện hình học ad-hoc. Mã ngắn hơn thắng.

Chỉnh sửa 1

Chúng tôi đang tìm kiếm một câu trả lời bằng thuật toán ở đây, không phải là một công cụ tìm phần thân lồi được lập trình sẵn như cái này trong MatLab hay cái này trong Mathicala

Chỉnh sửa 2

Trả lời ý kiến ​​và thông tin bổ sung:

  1. Bạn có thể giả sử danh sách đầu vào chứa số điểm tối thiểu phù hợp với bạn. Nhưng bạn phải đảm bảo điều trị thích hợp của các bộ (phụ) phù hợp.
  2. Bạn có thể tìm thấy các điểm lặp lại trong danh sách đầu vào
  3. Số lượng điểm tối đa chỉ được giới hạn bởi bộ nhớ khả dụng
  4. "Điểm nổi": Bạn cần có khả năng xử lý các danh sách đầu vào với tọa độ thập phân như được đưa ra trong các mẫu. Bạn có thể làm điều đó bằng cách sử dụng biểu diễn dấu phẩy động

.


2
Tôi dự đoán rằng MATLAB sẽ giành chiến thắng này.
Paul R

Chúng ta có thể cho rằng có ít nhất 3 điểm không? Chúng ta có thể cho rằng các điểm là khác biệt? Chúng tôi có cần phải hỗ trợ tọa độ điểm nổi không?
Peter Taylor

@PeterTaylor ví dụ cho thấy câu trả lời cuối cùng là đúng
John Dvorak

Chúng ta có thể ghi đè lên đầu vào không?
John Dvorak

Vấn đề với việc xử lý các điểm cộng tuyến nhất quán là có các vấn đề làm tròn. Chúng ta nên được phép phạm sai lầm.
John Dvorak

Câu trả lời:


2

Ruby, 168 ký tự

C=->q{r=[]
f=m=q.sort[0]
t=-0.5
(_,_,t,*f=q.map{|x,y|a=x-f[0]
b=y-f[1]
[0==(d=a*a+b*b)?9:(-t+e=Math.atan2(b,a)/Math::PI)%2,-d,e,x,y]}.sort[0]
r<<=f)while
!r[1]||f!=m
r}

Mã ruby ​​này cũng sử dụng thuật toán gói quà. Hàm Cchấp nhận một mảng các điểm và trả về vỏ lồi dưới dạng mảng.

Thí dụ:

>p C[[[4.4, 14], [6.7, 15.25], [6.9, 12.8], [2.1, 11.1], [9.5, 14.9], 
     [13.2, 11.9], [10.3, 12.3], [6.8, 9.5], [3.3, 7.7], [0.6, 5.1], [5.3, 2.4], 
     [8.45, 4.7], [11.5, 9.6], [13.8, 7.3], [12.9, 3.1], [11, 1.1]]]

[[5.3, 2.4], [11, 1.1], [12.9, 3.1], [13.8, 7.3], [13.2, 11.9], [9.5, 14.9], [6.7, 15.25], [4.4, 14], [2.1, 11.1], [0.6, 5.1]]

2

Toán học 151

vẫn đang làm việc

f = For[t = Sort@#; n = 1; l = Pi; a = ArcTan; c@1 = t[[1]],
       n < 2 || c@n != c@1, 
       n++,
      (l = a @@ (# - c@n); c[n + 1] = #) & @@
      t[[Ordering[Mod[a@## - l, 2 Pi] & @@ (#2 - #1) & @@@ Tuples@{{c@n}, t}, 1]]]] &

thử nghiệm:

ClearAll[a, c, t];
s = {{1, 0}, {0.68957, 0.283647}, {0.909487, 0.644276}, {0.0361877, 0.803816}, 
     {0.583004, 0.91555}, {-0.748169, 0.210483}, {-0.553528, -0.967036}, 
     {0.316709, -0.153861}, {-0.79267, 0.585945}, {-0.700164, -0.750994}, 
     {0.452273, -0.604434}, {-0.79134, -0.249902}, {-0.594918, -0.397574}, 
     {-0.547371, -0.434041}, {0.958132, -0.499614}, {0.039941, 0.0990732}, 
     {-0.891471, -0.464943}, {0.513187, -0.457062}, {-0.930053, 0.60341}, 
     {0.656995, 0.854205}};
f@s
Show[Graphics@Line@Table[c@i, {i, n}], 
     ListPlot[{t, Table[c@i, {i, n}]}, 
     PlotStyle -> {PointSize[Medium], PointSize[Large]}, 
     PlotRange -> All]]

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


1

Cà phê, 276:

f=($)->z=$[0];e.r=Math.atan2(e.x-z.x,e.y-z.y)for e in $;$.sort((x,y)->(x.r>y.r)-(x.r<y.r));(loop(a=$[i-1]||$[$.length-1];b=$[i];c=$[i+1]||$[0];break if!b;s=(b.x-a.x)*(c.y-b.y)-(b.y-a.y)*(c.x-b.x);break if s<0||!s&&(a.x-b.x)*(b.x-c.x)<0;$.splice i,1))for i in [$.length-1..0];$

Nếu chức năng không thể truy cập được, hãy xóa f=để loại bỏ thêm hai ký tự.

Đầu vào / đầu ra là một mảng các điểm duy nhất, với mỗi điểm được xác định bởi các x,ythuộc tính. Mảng đầu vào được sửa đổi, cũng như trả về (nếu không yêu cầu sau, loại bỏ hai ký tự cuối cùng).

Giải thích có thể được thêm vào sau.

Bộ thử nghiệm (sẽ không hoạt động trong oldIE):

alert JSON.stringify f({x:e[0], y:e[1]} for e in JSON.parse "
{{1, 1}, {2, 2}, ...}
".replace(/{/g,"[").replace(/}/g,"]"))

môi trường thử nghiệm được đề xuất: http://coffeescript.org/


Tôi đã thử nó {{1, 1}, {2, 2}, {3, 3}, {1, 3}}và nó trở lại [{"x" : 1, "y" : 1, "r" : 0}, {"x" : 1, "y" : 3, "r" : 0}, "x" : 2, "y" : 2, "r" : 0.78..}]trong khi tôi nghĩ câu trả lời đúng là một số hoán vị của{{3, 3}, {1, 3}, {1, 1}}
Tiến sĩ belisarius

Vấn đề @ Belisarius với các điểm cộng với điểm đầu tiên đôi khi tạo ra thân tàu không chính xác được cố định
John Dvorak

@belisarius vui lòng thêm điều này như một trường hợp thử nghiệm cho câu hỏi.
John Dvorak

Nó dường như hoạt động tốt ngay bây giờ :)
Tiến sĩ belisarius

1

Con trăn, 209 205 195

from math import*
s=lambda(a,b),(c,d):atan2(d-b,c-a)
def h(l):
 r,t,p=[],pi/2,min(l)
 while 1:
    q=min(set(l)-{p},key=lambda q:(s(p,q)-t)%(2*pi));m=s(p,q);r+=[p]*(m!=t);p=q;t=m
    if p in r:return r

Sử dụng một thuật toán gói quà. Kết quả bắt đầu với điểm ngoài cùng bên trái và kết thúc ngược chiều kim đồng hồ.

Ví dụ: h([(1, 1), (2, 2), (3, 3), (1, 3)])trả về[(1, 3), (1, 1), (3, 3)]


Bạn không cần một printđể có được đầu ra?
Tiến sĩ belisarius

Tôi nghĩ bởi "đầu ra" bạn có nghĩa là đầu ra của hàm. Bạn có muốn chức năng in kết quả thay vì trả lại không?
tông_box

Tôi nghĩ rằng yêu cầu the output list can be in any reasonable formatlà đủ rõ ràng. Bạn có nghĩ rằng nó cần phải được tuyên bố rõ ràng?
Tiến sĩ belisarius

Có vẻ như các điểm đầu ra của bạn không phải lúc nào cũng khớp với các điểm đầu vào nếu sử dụng dấu phẩy động. Ví dụ h([(0, 1), (0,1), (0.1 , 1)])cho tôi[(0, 1), (0.10000000000000001, 1)]
Tiến sĩ belisarius
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.