Điểm trong thân tàu lồi (2D)


10

Lý lịch

Vỏ lồi của một số điểm hữu hạn là đa giác lồi nhỏ nhất chứa tất cả các điểm, dưới dạng các đỉnh hoặc trên mặt trong. Để biết thêm thông tin, hãy xem câu hỏi này trên PGM, định nghĩa nó rất tốt .

Đầu vào

N+1Các tọa độ 2-D ( N >= 3) được truyền qua STDIN(với các đầu vào golf thông thường khác cũng được phép) theo định dạng sau (số thập phân có thể thay đổi nhưng bạn có thể giả sử nó vẫn "hợp lý" và mỗi số có thể được biểu thị dưới dạng nổi):

0.00;0.00000
1;0.00
0.000;1.0000
-1.00;1.000000

Đầu ra

Giá trị trung thực được in thành STDOUT(hoặc tương đương) nếu điểm đầu tiên trong danh sách ( (0.00;0.00000)trong ví dụ trên) nằm trong vỏ lồi của N điểm khác và giá trị giả khác.

Đây là , vì vậy giải pháp ngắn nhất tính bằng byte sẽ thắng.

  • Các trường hợp viền : bạn có thể trả về bất kỳ giá trị nào (nhưng không gặp sự cố) nếu điểm nằm trên đường viền của thân lồi (tức là ở một bên hoặc trên một đỉnh ở biên giới ngoài của thân tàu), vì đó là xác suất bằng không sự kiện (dưới bất kỳ xác suất hợp lý).

  • Cấm : mọi thứ (ngôn ngữ, toán tử, cấu trúc dữ liệu, tích hợp hoặc gói) chỉ tồn tại để giải quyết các vấn đề hình học (ví dụ: ConvexHull của Mathematica ). Các công cụ toán học có mục đích chung (vectơ, ma trận, số phức, v.v.) được cho phép.

Xét nghiệm


3
"Cấu trúc dữ liệu ad hoc" là gì?
DavidC

"Các hàm / toán tử cơ bản" quá mơ hồ.
xnor

@DavidCarraher: một cái gì đó như Đa giác, hoặc Tam giác hoặc Phân đoạn (bất cứ thứ gì tồn tại chỉ để giải quyết các vấn đề hình học).
Alexandre Halm

2
@AlexandreHalm Chỉnh sửa của bạn đã giúp rất nhiều. Tôi nghĩ "tiểu học" không phải là từ đúng. Tôi nghĩ rằng nó sẽ loại bỏ các mục đích chung được xây dựng như sorthoặc round. Tôi nghĩ rõ ràng hơn khi chỉ nói không có gì đặc biệt được làm cho hình học được cho phép. Mặc dù vậy, điều gì về một hàm để thêm hai danh sách dưới dạng vectơ? Hoặc một hàm để tìm đối số (góc) của một số phức?
xnor

1
Đây là lý do tại sao Kim cương yêu cầu mọi người vui lòng sử dụng Sandbox trước khi đăng các thử thách mới.
con mèo

Câu trả lời:


9

J, 40 39 34 byte

3 :'(o.1)<(>./-<./)12 o.y*+{.y'@:-

Hàm dyadic ẩn danh, lấy một điểm, p , làm một trong các đối số của nó và một danh sách các điểm, P , làm đối số khác (không quan trọng đó là đối số nào) và trả về 0hoặc 1, nếu p ở bên ngoài hoặc bên trong thân lồi của P , tương ứng. Điểm p và các điểm trong P , được lấy dưới dạng số phức.

Thí dụ

  is_inside =: 3 :'(o.1)<(>./-<./)12 o.y*+{.y'@:-

  0.5j0.5  is_inside  0j0 0j1 1j0 1j1
1
  1.5j0.5  is_inside  0j0 0j1 1j0 1j1
0

hoặc là...

Python 2, hàm, 121 103, chương trình đầy đủ, 162

Python 3, 149 byte

import sys,cmath as C
p,q,*P=[complex(*eval(l.replace(*";,")))for l in sys.stdin]
A=[C.phase((r-p)/(q-p+(q==p)))for r in P]
print(max(A)-min(A)>C.pi)

Đưa đầu vào, có cùng định dạng với bài đăng gốc, thông qua STDIN và in một giá trị boolean cho biết liệu p có nằm trong vỏ lồi của P không


Giải trình

Chương trình kiểm tra xem chênh lệch giữa góc tối đa và tối thiểu (đã ký) giữa bất kỳ điểm r nào trong P , p và điểm q tùy ý cố định trong P (chúng tôi chỉ sử dụng điểm đầu tiên trong P ), có nhỏ hơn 180 °. Nói cách khác, nó kiểm tra xem tất cả các điểm trong P có được chứa trong một góc 180 ° hoặc ít hơn, xung quanh p . p nằm trong vỏ lồi của P khi và chỉ khi điều kiện này là sai.


Với chi phí thêm một vài byte, chúng ta có thể sử dụng một phương pháp tương tự không yêu cầu chúng ta tính toán rõ ràng các góc: Lưu ý rằng điều kiện trên tương đương với việc nói rằng p nằm ngoài vỏ lồi của P khi và chỉ khi tồn tại một đường thẳng từ l đến p , sao cho tất cả các điểm trong P nằm cùng phía với l . Nếu một dòng như vậy tồn tại, thì cũng có một dòng như vậy xảy ra với một (hoặc nhiều) điểm trong P (chúng ta có thể xoay l cho đến khi chạm vào một trong các điểm trong P. )

Để (ngập ngừng) tìm dòng này, chúng tôi bắt đầu bằng cách cho phép l là dòng qua p và điểm đầu tiên trong P . Sau đó chúng tôi lặp lại các điểm còn lại trong P ; nếu một trong những điểm nằm ở bên trái của l (chúng ta giả sử một số hướng trong suốt, bên trái hoặc bên phải không thực sự quan trọng), chúng ta thay thế l bằng dòng đi qua p và điểm đó, và tiếp tục. Sau khi chúng tôi lặp lại trên tất cả P , nếu (và chỉ khi) p nằm ngoài thân lồi, thì tất cả các điểm trong P phải ở bên phải của (hoặc trên) l . Chúng tôi kiểm tra xem bằng cách sử dụng lần thứ hai qua các điểm trong P.

Python 2, 172 byte

import sys
P=[eval(l.replace(*";,"))for l in sys.stdin]
x,y=P.pop(0)
C=lambda(a,b),(c,d):(a-x)*(d-y)-(b-y)*(c-x)>0
l=reduce(lambda*x:x[C(*x)],P)
print any(C(l,q)for q in P)


Ngoài ra, để thực hiện điều tương tự trong một lần chạy, hãy đặt bên trái là một cảnh giới giữa hai điểm bất kỳ, qr , trong P , sao cho q nằm bên trái của r nếu q ở bên trái của dòng đi qua pr . Lưu ý rằng to-the-left-of là một mối quan hệ thứ tự trên P khi và chỉ khi tất cả các điểm trong P đang ở trên cùng một phía của một số dòng đi qua p , có nghĩa là, nếu p là bên ngoài thân tàu lồi của P . Quy trình được mô tả ở trên tìm thấy điểm tối thiểu trong PWRT lệnh này, ví dụ, điểm "tận cùng bên trái" tại P . Thay vì thực hiện hai lần chuyền, chúng ta có thể tìm điểm tối đa (nghĩa là điểm "ngoài cùng bên phải"), cũng như mức tối thiểu, các điểm trong P ghi cùng một thứ tự trong một lượt và xác minh rằng mức tối thiểu nằm ở bên trái của tối đa, tức là, một cách hiệu quả, từ bên trái sang phải là bắc cầu.

Điều này sẽ hoạt động tốt nếu p nằm ngoài vỏ lồi của P , trong trường hợp bên trái thực sự là một mối quan hệ trật tự, nhưng có thể bị phá vỡ khi p ở bên trong thân lồi (ví dụ: cố gắng tìm hiểu xem điều gì sẽ xảy ra nếu chúng ta chạy thuật toán này trong đó các điểm trong P là các đỉnh của một hình ngũ giác đều, chạy ngược chiều kim đồng hồ và p là tâm của nó.) Để phù hợp, chúng tôi thay đổi một chút thuật toán: Chúng tôi chọn một điểm q trong P và chia đôi P dọc theo đường đi qua pq (nghĩa là chúng ta phân vùng P quanh qwrt to-the-left-of.) Bây giờ chúng ta có một "phần bên trái" và "phần bên phải" của P , mỗi phần được chứa trong một nửa mặt phẳng, do đó, bên trái là một mối quan hệ thứ tự trên mỗi; chúng tôi tìm thấy tối thiểu của phần bên trái và tối đa của phần bên phải và so sánh chúng như mô tả ở trên. Tất nhiên, chúng ta không phải chia đôi P về mặt vật lý , chúng ta chỉ có thể phân loại từng điểm trong P khi chúng ta tìm kiếm mức tối thiểu và tối đa, trong một lần duy nhất.

Python 2, 194 byte

import sys
P=[eval(l.replace(*";,"))for l in sys.stdin]
x,y=P.pop(0)
C=lambda(a,b),(c,d):(a-x)*(d-y)-(b-y)*(c-x)>0
l=r=P[0]
for q in P:
 if C(P[0],q):l=q*C(l,q)or l
 elif C(q,r):r=q
print C(l,r)

bất kỳ cơ hội nào bạn có thể thực hiện các giải pháp của mình (ít nhất là giải pháp Python, tôi không biết liệu J có làm được không) lấy đầu vào từ STDIN? Tôi thấy việc so sánh các giải pháp với một sân chơi bình đẳng sẽ dễ dàng hơn. Giả sử rằng đầu vào đã là một tập hợp các số hoặc điểm phức tạp được định dạng sẵn là một chút của IMO kéo dài.
Alexandre Halm

@AlexandreHalm Đã thêm chương trình đầy đủ.
Ell

Bạn nên chia các giải pháp của bạn thành một câu trả lời cho mỗi ngôn ngữ.
Mego

4

Octave, 82 72 byte

d=dlmread(0,";");i=2:rows(d);~isna(glpk(i,[d(i,:)';~~i],[d(1,:)';1]))&&1

Ý tưởng là kiểm tra xem chương trình tuyến tính min {c'x: Ax = b, e'x = 1, x> = 0} có giải pháp hay không, trong đó e là một vectơ của tất cả các cột, các cột của A có tọa độ của đám mây điểm và b là điểm kiểm tra và c là tùy ý. Nói cách khác, chúng tôi cố gắng biểu diễn b dưới dạng tổ hợp lồi của các cột A.

Để chạy tập lệnh, sử dụng octave -f script.m <input.dat


2

R, 207 byte

d=read.csv(file("stdin"),F,";")
q=function(i,j,k)abs(det(as.matrix(cbind(d[c(i,j,k),],1))))
t=function(i,j,k)q(i,j,k)==q(1,i,j)+q(1,i,k)+q(1,j,k)
any(apply(combn(2:nrow(d),3),2,function(v)t(v[1],v[2],v[3])))

Kịch bản lấy đầu vào từ STDIN, vd Rscript script.R < inputFile.

Nó tạo ra tất cả các tam giác từ các Nđiểm cuối cùng (dòng cuối cùng apply(combn(...) và kiểm tra xem điểm đầu tiên có nằm trong tam giác hay không bằng cách sử dụng thàm.

tsử dụng phương thức diện tích để quyết định xem Ucó nằm trong ABC: (viết (ABC)cho vùng của ABC) Ulà trong ABCiff (ABC) == (ABU) + (ACU) + (BCU). Ngoài ra, các khu vực được tính toán bằng công thức xác định (xem tại đây để có bản demo đẹp từ Wolfram).

Tôi nghi ngờ giải pháp này dễ bị lỗi số hơn so với giải pháp khác của tôi, nhưng nó hoạt động trên các trường hợp thử nghiệm của tôi.


0

R, 282 byte

d=read.csv(file("stdin"),F,";")
p=function(a,b)a[1]*b[1]+a[2]*b[2]
t=function(a,b,c){A=d[a,];
U=d[1,]-A
B=d[b,]-A
C=d[c,]-A
f=p(C,C)
g=p(B,C)
h=p(U,C)
i=p(B,B)
j=p(U,B)
k=f*i-g*g
u=i*h-g*j
v=f*j-g*h
min(u*k,v*k,k-u-v)>0}
any(apply(combn(2:nrow(d),3),2,function(v)t(v[1],v[2],v[3])))

Kịch bản lấy đầu vào từ STDIN, vd Rscript script.R < inputFile.

Nó tạo ra tất cả các tam giác từ các Nđiểm cuối cùng (dòng cuối cùng apply(combn(...) và kiểm tra xem điểm đầu tiên có nằm trong tam giác hay không bằng cách sử dụng thàm.

tsử dụng phương pháp barycentric để quyết định xem Ulà trong ABC: (bằng văn bản XYcho Xđến Yvector) kể từ khi (AB,AC)là một cơ sở cho việc máy bay (trừ các trường hợp thoái hóa trong đó A, B, C thẳng hàng), AUcó thể được viết như sau AU = u.AB + v.ACUlà trong khi và chỉ khi tam giác u > 0 && v > 0 && u+v < 1. Xem ví dụ ở đây để giải thích chi tiết hơn và biểu đồ tương tác tốt đẹp. Lưu ý: để lưu một vài ký tự và tránh các lỗi DIV0, chúng tôi chỉ tính toán một phím tắt đến uvkiểm tra sửa đổi ( min(u*k,v*k,k-u-v)>0).

Các nhà khai thác chỉ toán học được sử dụng là +, -, *, min()>0.

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.