볼록 껍질 (2D)


10

배경

유한 한 점 의 볼록 껍질 은 정점 또는 내부의 모든 점을 포함하는 가장 작은 볼록 다각형입니다. 자세한 내용 은 PGM에 대한이 질문을 참조하십시오 .

입력

N+1다음 형식으로 N >= 3전달 된 2 차원 좌표 ( ) STDIN(다른 일반 골프 입력도 허용됨) (소수는 다를 수 있지만 "합리적"으로 유지되고 각 숫자는 부동으로 표시 될 수 있음) :

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

산출

인쇄에 truthy 값 STDOUT(목록의 첫 번째 지점 (또는 동등 물) (0.00;0.00000)의 예는 위의) 다른 N 지점의 볼록 헐이고, 그렇지 falsy 값.

이것은 이므로 바이트 단위의 최단 솔루션이 이깁니다.

  • 경계 사례 : 점이 볼록 껍질의 경계에있는 경우 (예 : 선체의 바깥쪽에있는 측면 또는 정점에있는) 임의의 값을 반환 할 수 있지만 충돌하지는 않습니다. 사건 (합당한 확률로).

  • 금지 : 존재 아무것도 (언어, 연산자, 데이터 구조, 내장 또는 패키지) 에만 기하학적 문제 (예 : 매스 매 티카의 해결하기 위해 볼록 포를 ). 범용 수학 도구 (벡터, 행렬, 복소수 등)가 허용됩니다.

테스트


3
"임시 데이터 구조"란 무엇입니까?
DavidC

"초등 함수 / 연산자"는 너무 모호합니다.
xnor

@DavidCarraher : 다각형, 삼각형 또는 세그먼트 (기하학적 문제를 해결하기 위해서만 존재하는 것)와 같은 것.
Alexandre Halm

2
@AlexandreHalm 당신의 편집이 많은 도움이되었습니다. "초등"이 옳지 않다고 생각합니다. 나는 그것이 같은 범용 내장 기능 제거 할 것이라고 생각 sort또는 round. 지오메트리를 위해 특별히 만들어진 것은 허용되지 않는다고 말하는 것이 더 분명하다고 생각합니다. 하지만 두 목록을 벡터로 추가하는 함수는 어떻습니까? 아니면 복소수의 인수 (각도)를 찾는 함수입니까?
xnor

1
이것이 다이아몬드가 사람들에게 새로운 도전을 게시하기 전에 샌드 박스사용하도록 요청하는 이유 입니다.
cat

답변:


9

제이, 40 39 34 바이트

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

익명 이항 함수는 점, 복용 P를 인수 중 하나와 지점의 목록으로, P (그것은 중요하지 어느 것이 어느 인수 않습니다) 다른 인수로, 그리고 반환 0하거나 1, 경우 p는 외부 또는 P 의 볼록 껍질 내부 . 점 p 및 점 P 는 복소수로 간주됩니다.

  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

또는...

파이썬 2, 함수, 121 103, 전체 프로그램, 162

파이썬 3, 149 바이트

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)

STDIN을 통해 원래 게시물과 동일한 형식으로 입력을 받고 p가 P의 볼록 껍질에 있는지 여부를 나타내는 부울 값을 인쇄합니다.


설명

최대 및 최소 (부호)의 차이가 임의의 점 사이의 각도 여부 프로그램 시험 연구 에서 P , P , 및 고정 된 임의의 점 Q 에서 P는 (우리는 단지 최초의 지점 사용 P를 , ° 미만 180 초과). 즉, P의 모든 점이 p 주위의 180 ° 이하의 각도에 포함되어 있는지 테스트합니다 . 이 조건이 거짓 인 경우에만 pP 의 볼록 껍질에 있습니다.


몇 바이트를 더 희생시키면서, 명시 적으로 각도를 계산할 필요가없는 비슷한 방법을 사용할 수 있습니다 : 위의 조건은 p 가 존재하는 경우에만 pP 의 볼록 껍질 밖에 있다고 말하는 것과 같습니다. P의 모든 점이 l 의 같은쪽에 있도록 l ~ p 선 . 이러한 라인이 존재하는 경우, 사건의 포인트 중 하나 (또는 그 이상)하는 것입니다 같은 라인도있다 P (는 우리가 할 수있는 회전 리터 가의 포인트 중 하나에 닿을 때까지 P .)

(가칭 적으로)이 선을 찾으려면 l을 통해 pP 의 첫 번째 점이되도록 합니다. 그런 다음 P 의 나머지 부분을 반복합니다 . 점들 중 하나가 l 의 왼쪽에 있다면 (우리는 전체적으로 약간의 방향성을 가정하고, 왼쪽이나 오른쪽은 실제로 중요하지 않다고 가정합니다) lp 와 그 점을 통과하는 선으로 바꾸고 계속합니다. 우리는 모든 반복 처리 후 P를 , 경우 (단 경우) (P)는 다음의 모든 포인트 볼록 선체 외부에 P가 (또는 페이지)의 오른쪽에 있어야 L . 우리는 P 의 포인트를 두 번째 패스로 사용하는지 확인합니다..

파이썬 2, 172 바이트

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)


또한,하자, 단일 패스에서 같은 일을하는 투 - 왼쪽의 두 점 사이의 realtion 수 QR 에서, P 있도록, q는 의 왼쪽에 R 경우 q는 왼쪽에 통과하는 라인 (P)R . 투 - 좌측의 상 순서 관계 참고 P는 경우 및 모든 지점에만 P를 통과하는 어떤 행의 동일 측에있는 P 경우이고, p는 의 볼록 선체 외부에 P . 위에서 설명한 절차는 P 에서 최소 점을 찾습니다.이 순서, 즉 P 의 "가장 왼쪽"점 . 대신 두 개의 패스를 수행하는, 우리는에서 포인트 최대 (즉, "오른쪽"점)뿐만 아니라, 최소를 찾을 수 있습니다 P는 단일 패스에서 같은 순서를 WRT, 최소이 (가) 왼쪽에 있는지 확인 가장 왼쪽, 즉 왼쪽은 전 이적입니다.

pP 의 볼록 껍질 바깥에 있으면 잘 작동합니다.이 경우 왼쪽에서 실제로는 주문 관계이지만 p 가 볼록 껍질 안에 있으면 깨질 수 있습니다 (예를 들어, P 의 점이 시계 반대 방향으로 실행되는 정 오각형의 정점이고 p 가 중심 인 위치에서이 알고리즘을 실행하면 발생합니다 .) 수용하기 위해 알고리즘을 약간 변경합니다 .P 에서 점 q 를 선택 하고 이등분합니다. pq를 통과하는 선을 따라 P (즉, 우리는 Pq 주위로 분할합니다.wrt to-the-left-of.) 이제 우리는 P 의 "왼쪽 부분"과 "오른쪽 부분"을 가지고 있으며 , 각각은 하프 플레인에 포함되어 있기 때문에 왼쪽부터 왼쪽은 각각의 순서 관계입니다. 왼쪽 부분의 최소값과 오른쪽 부분의 최대 값을 찾아 위에서 설명한대로 비교합니다. 물론, 우리는 P 를 물리적으로 양분 할 필요가 없으며 , 단일 패스에서 최소 및 최대를 찾을 때 P의 각 점을 간단히 분류 할 수 있습니다 .

파이썬 2, 194 바이트

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)

STDIN에서 솔루션을 가져올 수있는 기회가 있습니까? 솔루션을 레벨 경기장과 비교하는 것이 더 쉽다는 것을 알았습니다. 입력이 이미 미리 포맷 된 복소수 또는 점 집합이라고 가정하면 약간의 확장 IMO입니다.
Alexandre Halm

@AlexandreHalm 전체 프로그램을 추가했습니다.
Ell

언어별로 솔루션을 하나의 답변으로 분할해야합니다.
Mego

4

옥타브, 82 72 바이트

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

아이디어는 선형 프로그램 min {c'x : Ax = b, e'x = 1, x> = 0}에 해가 있는지 확인하는 것입니다. 여기서 e는 모든 것의 벡터이고 A의 열은 포인트 클라우드, b는 테스트 포인트이며 c는 임의입니다. 다시 말해, 우리는 b를 A의 열의 볼록한 조합으로 나타내려고합니다.

스크립트를 실행하려면 octave -f script.m <input.dat


2

R, 207 바이트

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])))

스크립트는 예를 들어 STDIN에서 입력을 가져옵니다 Rscript script.R < inputFile.

N마지막 점 (마지막 선 apply(combn(...) 에서 모든 삼각형을 생성 하고 t함수를 사용하여 첫 번째 점이 삼각형에 있는지 확인합니다 .

t만약 결정하는 영역에있어서 사용 U되어 ABC(쓰기 등 (ABC)의 영역 ABC) UABCIFF를 (ABC) == (ABU) + (ACU) + (BCU). 또한 면적은 결정 식을 사용하여 계산됩니다 ( Wolfram의 멋진 데모는 여기 참조 ).

이 솔루션이 다른 솔루션보다 수치 오류가 발생하기 쉽지만 테스트 사례에서 작동합니다.


0

R, 282 바이트

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])))

스크립트는 예를 들어 STDIN에서 입력을 가져옵니다 Rscript script.R < inputFile.

N마지막 점 (마지막 선 apply(combn(...) 에서 모든 삼각형을 생성 하고 t함수를 사용하여 첫 번째 점이 삼각형에 있는지 확인합니다 .

t만약 결정하는 무게 중심에있어서 사용 UABC(기록 XY대한 XY벡터) 이후 (AB,AC)(A, B, C가 정렬 축퇴 경우를 제외),면에 대한 기초를 AU같이 쓸 수 AU = u.AB + v.ACU삼각형 IFF에 u > 0 && v > 0 && u+v < 1. 더 자세한 설명과 멋진 대화 형 차트는 여기 를 참조하십시오 . 주의 : 우리는 단지에 바로 가기를 계산, 몇 문자와 회피 Div0을 오류를 저장 u하고 v및 수정 된 테스트 ( min(u*k,v*k,k-u-v)>0).

사용되는 유일한 산술 연산자는 +, -, *, min()>0.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.