Проблема щасливого Ендера


32

Проблема щасливого кінця (власне теорема) стверджує, що

Будь-який набір з п’яти точок у площині в загальному положенні має підмножину з чотирьох точок, які утворюють вершини опуклого чотирикутника.

Проблему так назвав Пол Ерд, коли двоє математиків, які вперше працювали над проблемою, Естер Кляйн та Джордж Секерес, одружилися та згодом одружилися.

Роз'яснення:

  • Загальна позиція тут означає, що жодні три пункти не є колінеарними.
  • Чотирикутник, утворений чотирма вершинами, завжди вважатиметься непересічним, незалежно від порядку точок. Наприклад, якщо чотири точки [1 1], [1 2], [2 1], [2 2]передбачуваний чотирикутник є квадратом, а НЕ бантик:

    введіть тут опис зображення

  • Чотирикутник, що не перетинається, опуклий, якщо жоден внутрішній кут не перевищує 180 градусів; або рівнозначно, якщо обидві діагоналі лежать всередині чотирикутника.

Змагання

Дано 5 точок з позитивними цілими координатами, виведіть 4 з цих точок, які утворюють опуклий чотирикутник.

Правила

Якщо є кілька рішень (тобто кілька наборів з 4 балів), ви можете послідовно вибрати одне з них або все.

Формати введення та виведення є гнучкими, як зазвичай (масиви, списки, список списків, рядки з розумними роздільниками тощо).

Код гольфу, виграє найменше байтів.

Тестові справи

  1. Вхід:

    [6 8] [1 10] [6 6] [5 9] [8 10]
    

    Є лише один можливий вихід:

    [6 8] [1 10] [6 6] [5 9]
    
  2. Вхід:

    [3 8] [7 5] [6 9] [7 8] [5 1]
    

    Є п'ять рішень:

    [3 8] [7 5] [6 9] [7 8]
    [3 8] [7 5] [6 9] [5 1]
    [3 8] [7 5] [7 8] [5 1]
    [3 8] [6 9] [7 8] [5 1]
    [7 5] [6 9] [7 8] [5 1]
    
  3. Вхід:

    [4 8] [1 9] [9 9] [10 2] [1 6]
    

    Є три рішення:

    [4 8] [1 9] [10 2] [1 6]
    [4 8] [9 9] [10 2] [1 6]
    [1 9] [9 9] [10 2] [1 6]
    

    Для ілюстрації, ось три рішення цього випадку:

введіть тут опис зображення


14
Я чекаю відповіді від Мартіна із вираженою позитивною емоцією.
El'endia Starman

1
Проблему щасливого кінця не слід плутати з проблемою щасливого Ендера, яка полягає в тому, щоб знайти спосіб запобігти військовим новобранцям виявити симуляції, які вони грають, справжні .
користувач253751

Відповіді:


24

CJam, 37 34 32 байт

{e!Wf<{2*3ew{)f.-~W%.*:-V>},!}=}

Не впевнений, чи :-Vдостатньо щасливий, але, як вказує К Чжан, =}це кінець. :)

Це друкує лише одне рішення, оскільки видалення дублікатів було б дорожчим.

Тестуйте це тут.

Пояснення

Ідея досить проста. Ми формуємо всі можливі чотирикутники (включаючи всі порядки точок), а потім просто вибираємо опуклі. Ми перевіряємо опуклість, дивлячись на кожну пару країв і перевіряючи, чи всі вони повертаються в одному напрямку.

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

e!       e# Generate all permutations of the five input points.
Wf<      e# Discard the fifth point in each permutations, giving all
         e# possible quadrilaterals.
{        e# Select the first for which this block gives a truthy result...
  2*     e#   Double the list of points, so that it includes each cyclically
         e#   adjacent set of three points.
  3ew    e#   Get all sublists of length 3, i.e. all sets of three consecutive
         e#   points (with two duplicates).
  {      e#   Filter these sets of three points...
    )    e#     Pull off the last point.
    f.-  e#     Subtract it from the other two, giving vectors from it to
         e#     to those.
    ~    e#     Unwrap the array dumping both vectors on the stack.
    W%   e#     Reverse one of them.
    .*   e#     Element-wise multiplication.
    :-   e#     Subtract the second element from the first. This completes
         e#     the projection.
    V>   e#     Check whether it's greater than 0. This is *false* for right-
         e#     turning sets of three points.
  },     e#   If all corners are right-turning, this will result
         e#   in an empty array.
  !      e#   Logical NOT - hence, only quadrilaterals where all corners
         e#   are right-turning give something truthy.
}=

2
Звичайно, щаслива качка!
Луїс Мендо

1
@LuisMendo Я думаю, останні два персонажі більше схожі на смайлик =}
K Чжан

!}можна також вважати підморгнення
Jezzamon

2
Джон Скіт з CodeGolf .. це дивовижно
Алекс Карлсен

8

MATLAB, 67 байт

I=input('');for k=~eye(5);if nnz(convhull(I(k,:)))>4;I(k,:),end;end

Введення виконується у вигляді 2D матриці, де стовпці - X та Y відповідно:

[6 8; 1 10; 6 6; 5 9; 8 10]
[3 8; 7 5; 6 9; 7 8; 5 1]
[4 8; 1 9; 9 9; 10 2; 1 6]

Усі набори з 4 точок, які створюють опуклі чотирикутники, відображаються в одному форматі.

Ось демонстрація, яка трохи змінена для роботи з Octave

Пояснення

Це рішення приймає всі підмножини з 4 балів вводу (порядок не має значення). Для цього ми створюємо одиничну матрицю і його заперечення: ~eye(5). Проводимо цикл через стовпці цієї матриці і k(індекс циклу) - це логічний масив, який визначає, який із 4-х пунктів слід врахувати. Потім ми використовуємо це, щоб захопити ці 4 точки XY з входу ( I(k,:)).

Потім обчислюємо опуклий корпус цих 4 точок ( convhull). Вихідні показники convhull- це показники введення, які відповідають точкам, що складають опуклий корпус (при цьому перший індекс дублюється для закриття корпусу).

Для опуклого чотирикутника всі чотири точки будуть частиною опуклого корпусу тих же точок ( nnz(convhull(points)) > 4). Якщо ми виявимо, що це так, ми відобразимо точки, які були використані для цієї конкретної ітерації.


4

Javascript (ES6), 306 293 283 байт

c=(v,w,x)=>(w[0]-v[0])*(w[1]-x[1])-(w[1]-v[1])*(w[0]-x[0])>0?1:0
i=(v,w,x,y)=>(c(v,w,x)+c(w,x,y)+c(x,y,v)+c(y,v,w))%4==0&&r.push([v,w,x,y])
j=(v,w,x,y)=>{i(v,w,x,y);i(v,w,y,x);i(v,x,w,y)}
k=(v,w,x,y,z)=>{j(v,w,x,y);j(v,w,x,z);j(v,w,y,z);j(v,x,y,z);j(w,x,y,z)}
f=(v)=>(r=[],k(...v),r)

Пояснення :

Функція cобчислює поперечний добуток вектора між 3 сусідніми точками багатокутника і повертає 1, якщо він є позитивним, а 0 в іншому випадку (зверніть увагу: поперечний добуток не може бути нульовим, оскільки точки не можуть бути ко-лінійними).

j=(v,w,x,y)=>{i(v,w,x,y);i(v,w,y,x);i(v,x,w,y)}
k=(v,w,x,y,z)=>{j(v,w,x,y);j(v,w,x,z);j(v,w,y,z);j(v,x,y,z);j(w,x,y,z)}

Функція kта jгенерування всіх циклічних перестановок (ігноруючи зворотний порядок) вхідного масиву.

i=(v,w,x,y)=>(c(v,w,x)+c(w,x,y)+c(x,y,v)+c(y,v,w))%4==0&&r.push([v,w,x,y])

Потім функція 'i' викликається для кожної циклічної перестановки для обчислення суми функції cдля кожної з 4 трійки суміжних координат. Якщо всі перехресні вироби мають один і той же знак, то всі вони будуть або 0, або 1 і всього 0 (модуль 4), а багатокутник є увігнутим і висувається у вихідний масив. Якщо будь-який триплет має інший знак, то загальна сума буде не нульовою (модуль 4), а багатокутник опуклий.

f=(v)=>(r=[],k(...v),r)

Функція fвикористовується для ініціалізації вихідного масиву, а потім виклику вищевказаних функцій перед поверненням виводу.

Тести :

c=(v,w,x)=>(w[0]-v[0])*(w[1]-x[1])-(w[1]-v[1])*(w[0]-x[0])>0?1:0
i=(v,w,x,y)=>(c(v,w,x)+c(w,x,y)+c(x,y,v)+c(y,v,w))%4==0&&r.push([v,w,x,y])
j=(v,w,x,y)=>{i(v,w,x,y);i(v,w,y,x);i(v,x,w,y)}
k=(v,w,x,y,z)=>{j(v,w,x,y);j(v,w,x,z);j(v,w,y,z);j(v,x,y,z);j(w,x,y,z)}
f=(v)=>(r=[],k(...v),r)

tests = [
  [[6,8],[1,10],[6,6],[5,9],[8,10]],
  [[3,8],[7,5],[6,9],[7,8],[5,1]],
  [[4,8],[1,9],[9,9],[10,2],[1,6]]
];

tests.forEach(
  (test,i)=>{
    console.log( "Test " + (i+1) );
    f(test).forEach(
      (x)=>console.log( "  " + x.map((e)=>"("+e[0]+","+e[1]+")").join(','))
    );
  }
);

Редагувати :

Також можна обробляти колінійні точки, використовуючи оригінальну версію та змінюючи перші два рядки на:

t=(a,b,c)=>Math.sign((b[0]-a[0])*(b[1]-c[1])-(b[1]-a[1])*(b[0]-c[0]))
p=(a,b,c,d)=>[t(a,b,c),t(b,c,d),t(c,d,a),t(d,a,b)].filter(x=>x).reduce((p,c,i,a)=>p&c==a[0],1)
q=(a,m,n,o)=>[a[0],a[m],a[n],a[o]]
f=(a)=>{r=[];for(i=0;i<5;i++){b=a.slice();b.splice(i,1);r.push(q(b,1,2,3));r.push(q(b,1,3,2));r.push(q(b,2,1,3))}return r.filter((a)=>p(...a))}

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


3

Mathematica 105 96 байт

Select[#~Subsets~{4},f@#&]&вибирає зі списку (5) балів ті підмножини з 4 балів, які задовольняють f.

fзадовольняються , коли кожна точка, з 4 точок в наборі, лежить на RegionBoundaryз ConvexHullз 4 -й точок.

f@p_:=Apply[And,RegionBoundary@ConvexHullMesh@p~RegionMember~#&/@p];
Select[#~Subsets~{4},f@#&]&

Випробування

1. Давайте подивимось на 5 опуклих корпусів підмножини (кожна з 4 точок) {{6, 8}, {1, 10}, {6, 6}, {5, 9}, {8, 10}} .

Select[#~Subsets~{4},f@#&[{{6, 8}, {1, 10}, {6, 6}, {5, 9}, {8, 10}}]

{{{6, 8}, {1, 10}, {6, 6}, {5, 9}}}


{{6, 8}, {1, 10}, {6, 6}, {5, 9}} - єдине рішення; кожна з чотирьох точок служить вершиною опуклого корпусу (з тих же 4-х точок).

рішення


{{6, 8}, {1, 10}, {6, 6}, {8, 10}} - це не рішення; опуклий корпус має лише 3 вершини. {6, 8} лежить всередині корпусу.

провал1


Решта підмножини також не є рішеннями:

провал2

провал3

провал4


2. {{4, 8}, {1, 9}, {9, 9}, {10, 2}, {1, 6}} має три рішення.

Select[#~Subsets~{4},f@#&[{{4, 8}, {1, 9}, {9, 9}, {10, 2}, {1, 6}}]

{
{{4, 8}, {1, 9}, {10, 2}, {1, 6}},
{{4, 8}, {9, 9}, {10, 2}, {1, 6 }},
{{1, 9}, {9, 9}, {10, 2}, {1, 6}}
}


3. {{3, 8}, {7, 5}, {6, 9}, {7, 8}, {5, 1}} має 5 рішень.

Select[#~Subsets~{4},f@#&[{{3, 8}, {7, 5}, {6, 9}, {7, 8}, {5, 1}}]

{
{{3, 8}, {7, 5}, {6, 9}, {7, 8}},
{{3, 8}, {7, 5}, {6, 9}, {5, 1 }},
{{3, 8}, {7, 5}, {7, 8}, {5, 1}},
{{3, 8}, {6, 9}, {7, 8}, {5 , 1}},
{{7, 5}, {6, 9}, {7, 8}, {5, 1}}
}

Зауважимо, що кожна з п'яти точок лежить на межі опуклого корпусу всіх точок.

Якщо будь-яку з точок видалити, то решта 4 бали будуть вершинами зменшеного опуклого корпусу.

sol2

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