Точка у опуклому корпусі (2D)


10

Фон

Опукла оболонка кінцевого числа точок є найменшим опуклим багатокутником , який містить всі точки, або в якості вершин або на внутрішній. Для отримання додаткової інформації дивіться це питання на PGM, яке дуже добре визначає його .

Вхідні дані

N+12-D координати ( N >= 3), пропущені STDIN(з іншими звичайними входами для гольфу також дозволено) у такому форматі (кількість десяткових знаків може змінюватися, але ви можете припустити, що він залишається "розумним", і кожне число може бути представлене як поплавок):

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

Вихідні дані

Цільова величина, надрукована на STDOUT(або еквівалент), якщо перша точка у списку ( (0.00;0.00000)у прикладі вище) знаходиться у опуклій корпусі інших N точок, а помилкове значення - в іншому випадку.

Це , тому найкоротше рішення в байтах виграє.

  • Кордонні випадки : ви можете повернути будь-яке значення (але не збиватися), якщо точка лежить на межі опуклого корпусу (тобто збоку або на вершині на зовнішній межі корпусу), оскільки це нульова ймовірність подія (за будь-якої розумної ймовірності).

  • Заборонено : будь-що (мова, оператор, структура даних, вбудований пакет або пакет), що існує лише для вирішення геометричних задач (наприклад, ContemxHull Mathematica ). Математичні засоби загального призначення (вектори, матриці, комплексні числа тощо) дозволені.

Тести


3
Що таке "спеціальна структура даних"?
DavidC

"елементарні функції / оператори" є занадто розпливчастими.
xnor

@DavidCarraher: щось на зразок багатокутника, трикутника або сегмента (все, що існує лише для вирішення геометричних задач).
Олександр Хальм

2
@AlexandreHalm Ваша редакція дуже допомогла. Я думаю, що "елементарне" - це не правильне слово. Я думав, що це усуне загальноприйняті вбудовані модулі типу sortабо round. Я думаю, що зрозуміліше просто сказати, що нічого спеціально зробленого для геометрії не дозволяється. Що, однак, щодо функції додавання двох списків як векторів? Або функція пошуку аргументу (кута) комплексного числа?
xnor

1
Ось чому Діаманти просять людей, будь ласка, використовуйте пісочницю, перш ніж публікувати нові виклики.
кіт

Відповіді:


9

J, 40 39 34 байти

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

Анонімна діадична функція, приймаючи крапку р як один із своїх аргументів і список точок Р як інший аргумент (не має значення, який аргумент є який), і повертається 0або 1, якщо р знаходиться поза або всередині опуклого корпусу 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

або ...

Python 2, функція, 121 103, повна програма, 162

Python 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


Пояснення

Програма перевіряє, чи різниця між максимальним та мінімальним (підписаними) кутами між будь-якою точкою r у P , p та фіксованою довільною точкою q у P (ми просто використовуємо першу точку P ) меншою ніж 180 °. Іншими словами, він перевіряє, чи містяться всі точки в Р під кутом 180 ° або менше, навколо p . p знаходиться у опуклому корпусі P тоді і лише тоді, коли ця умова хибна.


Ціною ще декількох байтів ми можемо скористатися аналогічним методом, який не вимагає від нас явного обчислення кутів: Зауважте, що вищевказана умова еквівалентна тому, що p є поза опуклим корпусом P, якщо і лише тоді, коли існує прямій l через p , так що всі точки в P знаходяться на одній стороні l . Якщо така лінія існує, то також існує така лінія, яка стикається з однією (або декількома) точками P (ми можемо обертати l, поки вона не торкнеться однієї з точок на P ).

Для того, щоб (попередньо) знайти цю лінію, ми почнемо, дозволяючи л бути прямий , що проходить через р і перша точка P . Потім ми повторюємо решту точок P ; якщо одна з точок знаходиться зліва від l (ми припускаємо, що деяка спрямованість на всьому протязі, ліва або права насправді не має значення), замінюємо l на пряму, що проходить через p і ту точку, і продовжуємо. Після того, як ми повторили весь 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)


Крім того, щоб зробити те ж саме за один прохід, нехай ліворуч буде реалізоване між будь-якими двома точками, q і r , в P , таким, що q знаходиться зліва від r, якщо q зліва лінії, що проходить через p і r . Зверніть увагу , що до-вліво від є відношення порядку P тоді і тільки тоді , коли всі точки Р знаходяться на одній і тій же боку деякої лінії , що проходить через р , тобто, якщо р знаходиться поза опуклої оболонки P . Описана вище процедура знаходить мінімальну точку PWRT цей порядок, тобто «крайній лівий» точку P . Замість виконання двох проходів ми можемо знайти максимум (тобто "найправіший" пункт), а також мінімальний, точки в P wrt того ж порядку в одному проході і перевірити, що мінімум знаходиться зліва від максимум, тобто ефективно, що ліворуч є перехідним.

Це буде добре, якщо p знаходиться поза опуклим корпусом P , в цьому випадку ліворуч - це фактично відношення порядку, але може зламатися, коли p знаходиться всередині опуклого корпусу (наприклад, спробуйте розібратися, що буде відбудеться , якщо ми запустили цей алгоритм , де точки в р є вершинами правильного п'ятикутника, працює проти годинникової стрілки, і п . є його центром) Для розміщення, ми трохи змінити алгоритм: ми вибираємо точку д в р , і Bisect P по лінії, що проходить через p і q (тобто, розділимо P навколо qwrt to-left-of.) Тепер у нас є "ліва частина" і "права частина" P , кожна з яких міститься в півплощині, так що ліворуч - це відношення порядку для кожної; ми знаходимо мінімум лівої частини та максимум правої частини та порівняємо їх, як описано вище. Звичайно, нам не доводиться фізично ділити P , ми можемо просто класифікувати кожну точку P, оскільки ми шукаємо мінімум і максимум за один прохід.

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

будь-який шанс, що ви могли б зробити свої рішення (принаймні, Python, я не маю поняття, якщо J можу це зробити) взяти внесок від STDIN? Я вважаю, що було б простіше порівняти рішення з рівними умовами. Якщо припустити, що вхід є вже заздалегідь відформатованим набором складних чисел або точок, це трохи розтягнутий ІМО.
Олександр Халм

@AlexandreHalm Додано повну програму.
Елл

Ви повинні розділити свої рішення на одну відповідь на кожну мову.
Мего

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) Uзнаходиться в ABCiff (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використовує барицентрична метод , щоб вирішити , якщо Uв ABC: (записи XYдля Xдо Yвектору) , оскільки (AB,AC)є основою для площині (для вироджених випадків , коли вирівняні А, В, С , за виключення), AUможе бути записана в вигляді AU = u.AB + v.ACі Uзнаходиться в трикутнику МФЛ u > 0 && v > 0 && u+v < 1. Дивіться, наприклад, тут для більш детального пояснення та приємного інтерактивного діаграми. Примітка: щоб зберегти кілька знаків і уникнути помилок DIV0, ми обчислимо лише ярлик до uта vмодифікований тест ( min(u*k,v*k,k-u-v)>0).

Єдиний математичні оператори використовуються +, -, *, min()>0.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.