El feliz problema de Ender

32

El problema de final feliz (en realidad un teorema) establece que

Cualquier conjunto de cinco puntos en el plano en posición general tiene un subconjunto de cuatro puntos que forman los vértices de un cuadrilátero convexo.

El problema fue llamado así por Paul Erdős cuando dos matemáticos que trabajaron por primera vez en el problema, Ester Klein y George Szekeres, se comprometieron y posteriormente se casaron.

Aclaraciones:

  • La posición general aquí significa que no hay tres puntos colineales.
  • El cuadrilátero formado por los cuatro vértices siempre se considerará que no se cruza, independientemente del orden de los puntos. Por ejemplo, teniendo en cuenta los cuatro puntos [1 1], [1 2], [2 1], [2 2]el cuadrilátero intención es la plaza, no la corbata de lazo:

    ingrese la descripción de la imagen aquí

  • Un cuadrilátero que no se cruza es convexo si ningún ángulo interior excede los 180 grados; o equivalente si ambas diagonales se encuentran dentro del cuadrilátero.

El reto

Dados 5 puntos con coordenadas enteras positivas, genera 4 de esos puntos que forman un cuadrilátero convexo.

Reglas

Si hay varias soluciones (es decir, varios conjuntos de 4 puntos), puede optar constantemente por generar uno o todos.

Los formatos de entrada y salida son flexibles como de costumbre (matrices, listas, lista de listas, cadenas con separadores razonables, etc.).

Código de golf, menos bytes gana.

Casos de prueba

  1. Entrada:

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

    Solo hay una salida posible:

    [6 8] [1 10] [6 6] [5 9]
    
  2. Entrada:

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

    Hay cinco soluciones:

    [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. Entrada:

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

    Hay tres soluciones:

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

    Para ilustrar, aquí están las tres soluciones para este caso:

ingrese la descripción de la imagen aquí

Luis Mendo
fuente
14
Estoy esperando una respuesta de Martin con una emoción positiva expresada allí.
El'endia Starman
1
El problema de final feliz no debe confundirse con el problema de Ender feliz, que es encontrar una manera de evitar que los reclutas militares descubran que las simulaciones que están jugando son reales .
user253751

Respuestas:

24

CJam, 37 34 32 bytes

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

No estoy seguro de si :-Ves lo suficientemente feliz, pero como señala K Zhang, está =}el final. :)

Esto solo imprime una solución porque eliminar duplicados sería más costoso.

Pruébalo aquí.

Explicación

La idea es bastante simple. Generamos todos los cuadriláteros posibles (incluidos todos los ordenamientos de los puntos) y luego solo seleccionamos los convexos. Probamos la convexidad observando cada par de bordes y verificando que todos estén girando en la misma dirección.

El sentido de giro se puede obtener con bastante facilidad de un producto de punto. Si toma los tres puntos consecutivos en un cuadrilátero, y dibuja líneas del primero al segundo, y del primero al tercero, y luego proyecta el último en la perpendicular del primero ... obtendrá un número cuyo signo le indica si estos tres puntos giran a la izquierda o a la derecha. (Probablemente debería agregar un diagrama para esto). Esta "proyección sobre la perpendicular" suena bastante complicada, pero en realidad solo significa que invertimos uno de los dos vectores y restamos los componentes después de la multiplicación en lugar de sumarlos. Así que aquí está el código ...

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.
}=
Martin Ender
fuente
2
Claro, un pato feliz!
Luis Mendo
1
@LuisMendo Creo que los dos últimos personajes se parecen más a un smiley =}
K Zhang
!}también podría considerarse un guiño
Jezzamon
2
Jon Skeet de CodeGolf .. esto es increíble
Alex Carlsen
8

MATLAB, 67 bytes

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

La entrada tiene la forma de una matriz 2D donde las columnas son X e Y respectivamente:

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

Todos los conjuntos de 4 puntos que crean cuadriláteros convexos se muestran en el mismo formato.

Aquí hay una demostración que está ligeramente modificada para funcionar con Octave

Explicación

Esta solución toma todos los subconjuntos de 4 puntos de la entrada (el orden no importa). Para ello, creamos la matriz identidad y negar que: ~eye(5). Recorremos las columnas de esta matriz y k(el índice del ciclo) es una matriz lógica que especifica cuál de los 4 puntos a considerar. Luego usamos esto para tomar estos 4 puntos XY de la entrada ( I(k,:)).

Luego calculamos el casco convexo de estos 4 puntos ( convhull). La salida de convhullson los índices de la entrada que se corresponden con los puntos que conforman el casco convexo (con el primer índice duplicado para cerrar el casco).

Para un cuadrilátero convexo, los cuatro puntos serán parte del casco convexo de los mismos puntos ( nnz(convhull(points)) > 4). Si detectamos que este es el caso, mostramos los puntos que se utilizaron para esta iteración en particular.

Suever
fuente
4

Javascript (ES6), 306 293 283 bytes

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)

Explicacion :

La función ccalcula el producto cruzado del vector entre 3 puntos adyacentes del polígono y devuelve 1 si es positivo y 0 de lo contrario (nota: el producto cruzado no puede ser cero ya que los puntos no pueden ser co-lineales).

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

La función ky jgenera todas las permutaciones cíclicas (ignorando invertir el orden) de la matriz de entrada.

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

Luego se llama a la función 'i' para cada permutación cíclica para calcular la suma de la función cpara cada una de las 4 tripletas de coordenadas adyacentes. Si todos los productos cruzados tienen el mismo signo, todos serán 0 o 1 y totalizarán 0 (módulo 4) y el polígono es cóncavo y se inserta en la matriz de salida. Si algún triplete tiene un signo diferente, el total será distinto de cero (módulo 4) y el polígono es convexo.

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

La función fse usa para inicializar la matriz de salida y luego llamar a las funciones anteriores antes de devolver la salida.

Pruebas :

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(','))
    );
  }
);

Editar :

También puede manejar puntos co-lineales usando la versión original y cambiando las dos primeras líneas a:

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

Sin embargo, dado que ese caso se excluye específicamente en la pregunta, los caracteres adicionales no son necesarios.

MT0
fuente
3

Mathematica 105 96 bytes

Select[#~Subsets~{4},f@#&]&selecciona, de una lista de (5) puntos, aquellos subconjuntos de 4 puntos que satisfacen f.

fse satisface cuando cada punto, de los 4 puntos en un conjunto, se encuentra en RegionBoundaryel ConvexHullde los 4 puntos.

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

Casos de prueba

1. Veamos los 5 cascos convexos de subconjuntos (cada uno de 4 puntos) de {{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}} es la única solución; cada uno de los cuatro puntos sirve como vértice del casco convexo (de los mismos 4 puntos).

solución


{{6, 8}, {1, 10}, {6, 6}, {8, 10}} no es una solución; El casco convexo tiene solo 3 vértices. {6, 8} se encuentra dentro del casco.

fallar1


Los subconjuntos restantes tampoco son soluciones:

fail2

fallar3

fallar4


2. {{4, 8}, {1, 9}, {9, 9}, {10, 2}, {1, 6}} tiene tres soluciones.

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}} tiene 5 soluciones.

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}}
}

Tenga en cuenta que cada uno de los cinco puntos se encuentra en el límite del casco convexo de todos los puntos.

Si se elimina cualquiera de los puntos, los 4 puntos restantes serán vértices del casco convexo reducido.

sol2

DavidC
fuente