Il felice problema di Ender


32

Il problema del lieto fine (in realtà un teorema) lo afferma

Qualsiasi insieme di cinque punti nel piano in posizione generale ha un sottoinsieme di quattro punti che formano i vertici di un quadrilatero convesso.

Il problema è stato chiamato così da Paul Erdős quando due matematici che per primi hanno lavorato al problema, Ester Klein e George Szekeres, si sono fidanzati e successivamente si sono sposati.

chiarimenti:

  • La posizione generale qui significa che nessun punto è collineare.
  • Il quadrilatero formato dai quattro vertici sarà sempre considerato non intersecante, indipendentemente dall'ordine dei punti. Ad esempio, in quattro punti [1 1], [1 2], [2 1], [2 2]il quadrilatero previsto è il quadrato, non il cravattino:

    inserisci qui la descrizione dell'immagine

  • Un quadrilatero non intersecante è convesso se nessun angolo interno supera i 180 gradi; o equivalentemente se entrambe le diagonali si trovano all'interno del quadrilatero.

La sfida

Dati 5 punti con coordinate intere positive, emettere 4 di quei punti che formano un quadrilatero convesso.

Regole

Se esistono diverse soluzioni (ovvero diversi set di 4 punti), è possibile scegliere costantemente di emetterne una o tutte.

I formati di input e output sono flessibili come al solito (array, elenchi, elenchi di elenchi, stringhe con separatori ragionevoli, ecc.).

Codice golf, vince il minor numero di byte.

Casi test

  1. Ingresso:

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

    Esiste un solo output possibile:

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

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

    Esistono cinque soluzioni:

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

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

    Esistono tre soluzioni:

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

    Per illustrare, ecco le tre soluzioni a questo caso:

inserisci qui la descrizione dell'immagine


14
Mi aspetto una risposta da Martin con un'emozione positiva espressa in esso.
El'endia Starman,

1
Il problema del lieto fine non deve essere confuso con il felice problema dell'Ender, che è quello di trovare un modo per impedire alle reclute militari di scoprire che le simulazioni a cui stanno giocando sono reali .
user253751

Risposte:


24

CJam, 37 34 32 byte

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

Non sono sicuro che :-Vsia abbastanza felice, ma come sottolinea K Zhang, c'è =}la fine. :)

Questo stampa solo una soluzione perché rimuovere i duplicati sarebbe più costoso.

Provalo qui.

Spiegazione

L'idea è abbastanza semplice. Generiamo tutti i quadrilateri possibili (compresi tutti gli ordinamenti dei punti) e quindi selezioniamo solo quelli convessi. Testiamo la convessità osservando ogni coppia di spigoli e verificando che ruotino tutti nella stessa direzione.

Il senso di rotazione può essere ottenuto abbastanza facilmente da un prodotto a punti. Se prendi i tre punti consecutivi su un quadrilatero e disegni le linee dal primo al secondo, e dal primo al terzo, e poi proietti il ​​secondo sulla perpendicolare del primo ... ottieni un numero il cui segno ti dice se questi tre punti girano a sinistra o a destra. (Probabilmente dovrei aggiungere un diagramma per questo.) Questo "proiettare sulla perpendicolare" è un suono abbastanza coinvolto, ma in realtà significa solo che invertiamo uno dei due vettori e sottraggiamo i componenti dopo la moltiplicazione invece di aggiungerli. Quindi ecco il codice ...

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
Certo, un'anatra felice!
Luis Mendo,

1
@LuisMendo Penso che gli ultimi due personaggi assomiglino più a una faccina =}
K Zhang

!}potrebbe essere considerato anche un occhiolino
Jezzamon

2
Jon Skeet di CodeGolf .. questo è fantastico
Alex Carlsen,

8

MATLAB, 67 byte

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

L'input ha la forma di una matrice 2D in cui le colonne sono rispettivamente X e 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]

Tutti i set di 4 punti che creano quadrilateri convessi vengono visualizzati nello stesso formato.

Ecco una demo che è leggermente modificata per funzionare con Octave

Spiegazione

Questa soluzione accetta tutti i sottoinsiemi di 4 punti dell'input (l'ordine non ha importanza). Per fare questo, creiamo la matrice identità e negarlo: ~eye(5). Passiamo attraverso le colonne di questa matrice e k(l'indice del ciclo) è un array logico che specifica quale dei 4 punti considerare. Usiamo quindi questo per afferrare questi 4 punti XY dall'input ( I(k,:)).

Quindi calcoliamo lo scafo convesso di questi 4 punti ( convhull). L'output di convhullsono gli indici dell'input che corrispondono ai punti che compongono lo scafo convesso (con il primo indice duplicato per chiudere lo scafo).

Per un quadrilatero convesso, tutti e quattro i punti faranno parte dello scafo convesso degli stessi punti ( nnz(convhull(points)) > 4). Se rileviamo che questo è il caso, visualizziamo i punti utilizzati per questa particolare iterazione.


4

Javascript (ES6), 306 293 283 byte

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)

Spiegazione :

La funzione ccalcola il prodotto incrociato del vettore tra 3 punti adiacenti del poligono e restituisce 1 se è positivo e 0 altrimenti (nota: il prodotto incrociato non può essere zero poiché i punti non possono essere co-lineari).

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 funzione ke jgenera tutte le permutazioni cicliche (ignorando l'inversione dell'ordine) dell'array di input.

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

La funzione 'i' viene quindi chiamata per ciascuna permutazione ciclica per calcolare la somma della funzione cper ciascuna delle 4 terzine di coordinate adiacenti. Se i prodotti incrociati hanno tutti lo stesso segno, saranno tutti o 0 o 1 e un totale di 0 (modulo 4) e il poligono è concavo e viene inserito nell'array di output. Se una tripletta ha un segno diverso, il totale sarà diverso da zero (modulo 4) e il poligono è convesso.

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

La funzione fviene utilizzata per inizializzare l'array di output e quindi chiamare le funzioni sopra prima di restituire l'output.

Test :

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

Edit :

Può anche gestire punti co-lineari usando la versione originale e cambiando le prime due linee in:

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

Tuttavia, poiché quel caso è specificamente escluso dalla domanda, i caratteri extra non sono necessari.


3

Mathematica 105 96 byte

Select[#~Subsets~{4},f@#&]&seleziona, da un elenco di (5) punti, quei sottoinsiemi di 4 punti che soddisfano f.

fè soddisfatto quando ogni punto, dei 4 punti di un set, giace sul RegionBoundarydei ConvexHulldei 4 punti.

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

Casi test

1. Diamo un'occhiata ai 5 scafi convessi di sottoinsiemi (ciascuno di 4 punti) di {{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}} è l'unica soluzione; ciascuno dei quattro punti funge da vertice dello scafo convesso (degli stessi 4 punti).

soluzione


{{6, 8}, {1, 10}, {6, 6}, {8, 10}} non è una soluzione; lo scafo convesso ha solo 3 vertici. {6, 8} si trova all'interno dello scafo.

fail1


Anche i restanti sottoinsiemi non sono soluzioni:

fail2

fail3

fail4


2. {{4, 8}, {1, 9}, {9, 9}, {10, 2}, {1, 6}} ha tre soluzioni.

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}} ha 5 soluzioni.

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

Si noti che ciascuno dei cinque punti si trova sul bordo dello scafo convesso di tutti i punti.

Se viene rimosso uno qualsiasi dei punti, i restanti 4 punti saranno ciascuno vertici dello scafo convesso ridotto.

SOL2

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.