Problema di scissione della collana


19

sfondo

Sono stato ispirato dal recente video di 3Blue1Brown sul problema della divisione della collana (o come lo chiama lui, il problema della collana rubata) e sulla sua relazione con il teorema di Borsuk-Ulam .

In questo problema, due ladri hanno rubato una preziosa collana composta da diversi tipi di gioielli. Esiste un numero pari di ogni tipo di gioiello e i ladri desiderano dividere ogni tipo di gioiello in modo uniforme tra i due. Il trucco è che devono farlo dividendo la collana in un certo numero di segmenti contigui e distribuendo i segmenti tra loro due.

Ecco un esempio con quattro tipi gioiello indicati S, E, D, e R(per zaffiro, smeraldo, diamante e rubino, rispettivamente). Diciamo che la collana è la seguente:

[S,S,S,E,S,D,E,R,S,R,E,S,S,S,D,R,E,E,R,E,D,E,R,R,D,E,E,E]

Ci sono 8zaffiri, 10smeraldi, 4diamanti e 6rubini. Possiamo dividere la collana come segue:

[[S],[S],[S,E,S,D,E,R,S],[R,E,S,S,S,D,R,E,E,R,E,D,E],[R,R,D,E,E,E]]

Quindi se diamo il primo, il terzo e il quinto segmento a un ladro e il secondo e il quarto segmento all'altro ladro, ognuno finirà con 4zaffiri, 5smeraldi, 2diamanti e 3rubini:

[S],    [S,E,S,D,E,R,S],                            [R,R,D,E,E,E]
    [S],                [R,E,S,S,S,D,R,E,E,R,E,D,E],

Usando 0-indexing, questi tagli si verificano negli indici [1,2,9,22].

Obbiettivo

Si scopre che una divisione così equa può sempre essere fatta usando al massimo i ntagli, dove si ntrova il numero di tipi di gioielli. Il tuo compito è quello di scrivere un programma o una funzione completa che accetta una collana come input e genera una divisione minima (il minor numero di tagli).

Ingresso

L'input può essere in qualsiasi formato conveniente. La collana dovrebbe essere una sequenza di gioielli e niente di più; ad esempio un elenco di numeri interi, un dizionario con chiavi che rappresentano i tipi di gioiello e i valori che sono elenchi di indici. Puoi facoltativamente includere la lunghezza della collana o il numero di tipi di gioiello distinti, ma non dovresti prendere altri input.

Si può presumere che la collana di input sia valida. Non è necessario gestire il caso in cui esiste un numero dispari di gioielli di un determinato tipo o la collana è vuota.

Produzione

Ancora una volta, l'output può essere in qualsiasi formato conveniente; ad esempio un elenco di segmenti, un elenco di posizioni di taglio, un dizionario con chiavi che rappresentano i due ladri e valori che sono elenchi di segmenti, ecc. I segmenti possono essere rappresentati dal loro indice iniziale, indice finale, elenco di indici consecutivi, elenco di gioielli, le loro lunghezze, ecc. Puoi usare 0- o 1- l'indicizzazione. Se l'ordinamento non è significativo per il tuo formato, l'output potrebbe essere in qualsiasi ordine. Ecco l'output sopra in diversi formati:

list of segments: [[S],[S],[S,E,S,D,E,R,S],[R,E,S,S,S,D,R,E,E,R,E,D,E],[R,R,D,E,E,E]]
list of cuts:     [1,2,9,22]
list of lengths:  [1,1,7,13,6]
dictionary:       {'thief1' : [(R,R,D,E,E,E),(S),(S,E,S,D,E,R,S)], 'thief2' : [(S),(R,E,S,S,S,D,R,E,E,R,E,D,E)]}

Si noti che l'ordine è importante nell'elenco dei segmenti (i segmenti si alternano tra i ladri) e l'elenco delle lunghezze (per identificare i segmenti), ma non nell'elenco dei tagli o nel dizionario. Modifica: Greg Martin ha sottolineato che questi non sarebbero risultati validi poiché una divisione equa può essere ottenuta in due tagli

Casi test

[1,2,1,2,1,3,1,3,3,2,2,3] -> [[1,2,1],[2,1,3,1],[3,3,2],[2,3]]
[1,1,1,1,2,2,3,3,3,3,3,3] -> [[1,1],[1,1,2],[2,3,3,3],[3,3,3]]
[1,1,1,1,1,1,1,1,1,1,1,1] -> [[1,1,1,1,1,1],[1,1,1,1,1,1]]
[1,1,1,1,2,3,4,2,3,4,2,2] -> [[1,1],[1,1,2,3,4,2],[3,4,2,2]]

Appunti

  1. Sono vietate le scappatoie standard .
  2. Questo è ; la risposta più breve (in byte) vince.

2
La collana è circolare?
Dennis,

1
@Dennis No, la collana è lineare.
ngenesi,

1
Possiamo prendere l'input come lettere / token che indicano i diversi tipi di gioiello, anziché numeri interi?
Greg Martin,

3
Se l'ordine dei segmenti non viene modificato, i pezzi si alternano tra la lettera A e la lettera B. In quanto tale, inclusa l'informazione nell'output è ridondante. Possiamo omettere l'indicazione se la risposta non cambia l'ordine dei gioielli? Hai alcuni casi di test?
Luca,

2
Per il tuo esempio [S,S,S,E,S,D,E,R,S,R,E,S,S,S,D,R,E,E,R,E,D,E,R,R,D,E,E,E], sembra che l'output dovrebbe essere [[S,S,S,E,S,D,E,R],[S,R,E,S,S,S,D,R,E,E,R,E,D,E],[R,R,D,E,E,E]], dal momento che ha meno tagli di [[S],[S],[S,E,S,D,E,R,S],[R,E,S,S,S,D,R,E,E,R,E,D,E],[R,R,D,E,E,E]]. Comprendo correttamente le specifiche?
Greg Martin,

Risposte:


3

Brachylog , 13 byte

~c.ġ₂z₁Ċcᵐoᵛ∧

Provalo online!

Nota: il metapredicato è più recente di questa sfida.

Spiegazione

~c.ġ₂z₁Ċcᵐoᵛ∧  Input is a list, say L = [1,2,2,2,1,2,3,3]
~c.            Output is a partition of the input: [[1,2,2],[2,1,2],[3],[3]]
  .ġ₂          Split the output into chunks of length 2: [[[1,2,2],[2,1,2]],[[3],[3]]]
     z₁        Zip (transpose) the chunks: [[[1,2,2],[3]],[[2,1,2],[3]]]
       Ċ       This is a 2-element list (forbid the trivial partition).
        cᵐ     Concatenate both: [[1,2,2,3],[2,1,2,3]]
          oᵛ   If you sort both lists, they are equal.
            ∧  Don't unify with the output.

Le partizioni sono elencate in ordine crescente del numero di blocchi, quindi il risultato avrà il minor numero di blocchi possibile.


3

Gelatina , 18 byte

s2ZFṢ$€E¬,L
ŒṖṖÇÞḢ

Provalo online!

Non efficiente - l'esempio ha 28 gioielli che non funzioneranno senza enormi risorse poiché il primo passo di questa implementazione sarebbe quello di costruire un elenco delle 2 27 possibili partizioni.

Restituisce un elenco di elenchi: i segmenti nell'ordine per distribuirli tra i ladri alternativi. (Per quanto riguarda l'output TIO: quando un elenco ha solo un singolo elemento, la stampa implicita non si preoccupa delle parentesi, [])

Come?

s2ZFṢ$€E¬,L - Link 1, get (isUnfair, Slices): A possible partition
s2          - split into slices of length 2 (any odd one on it's own at the end)
  Z         - transpose (first item is one thief's slices, second is the others)
     $€     - last two links as a monad for €ach
   F        -     flatten
    Ṣ       -     sort
       E    - equal? (theif1's jewels == theif2's jewels)
        ¬   - not
          L - length (number of slices in the partition)
         ,  - pair

ŒṖṖÇÞḢ - Main link: necklace
ŒṖ     - all partitions
  Ṗ    - pop, we must remove the rightmost one...
              because Link 1 will say it is fair, and it will have length 1!
              (a list of one thing has all entries equal)
    Þ  - sort by
   Ç   -     last link (1) as a monad
     Ḣ - head (get the first one, i.e. minimal isUnfair, then minimal length)

3

Mathematica, 118 byte

Quasi battuto Jelly ... solo 1 di sconto;)

SelectFirst[l_±c_:=Append[-#±Most@c,#2]&@@l~TakeDrop~Last@c;l_±{}:={l};i=#;(i±#)&/@Range@#2~Subsets~#3,Tr[Tr/@#]==0&]&

Pura funzione prendendo tre argomenti: la collana, come un elenco di token come {A, A, A, A, B, C, D, B, C, D, B, B}; la lunghezza della collana; e il numero di tempi gioiello distinti. Restituisce un elenco di elenchi secondari nella forma {{A, A}, {-A, -A, -B, -C, -D, -B}, {C, D, B, B}}, in cui i token senza segni negativi vanno a un ladro e i token con segni negativi vanno all'altro ladro. (Sebbene si tratti di informazioni ridondanti, l'algoritmo porta a questa rappresentazione e la rimozione dei segni negativi costerebbe diversi byte.)

Innanzitutto dobbiamo implementare una funzione che prende un elenco e un insieme di npunti di interruzione e restituisce l'elenco di elenchi n+1secondari ottenuti tagliando l'elenco di input in quei punti di ninterruzione; l'operatore di infissione binaria ±viene utilizzato per questo scopo e definito in modo ricorsivo l_±c_:=Append[-#±Most@c,#2]&@@l~TakeDrop~Last@c;l_±{}:={l};. A causa del segno negativo subito dopo Append, il risultato è che le liste secondarie si alternano e non hanno segni negativi associati a ciascun token.

Quindi generiamo tutti i possibili set di cut-place la cui lunghezza è al massimo il numero di tipi di gioiello, utilizzando Range@#2~Subsets~#3e utilizzare i=#;(i±#)&/@per applicare l' ±operatore (con l'elenco di input dei gioielli) a ciascuno di questi set di cut-place a turno.

Infine, SelectFirst[...,Tr[Tr/@#]==0&]&seleziona la prima delle divisioni di collana risultanti che è giusta. Lo fa sommando letteralmente tutti gli elementi in tutte le liste secondarie; Mathematica è abbastanza saggia da cancellare le copie positive e negative di ogni token in modo ovvio.


3

Pyth, 16 byte

hfqFSMsM.TcT2t./

Provalo online: Dimostrazione o Test Suite

Spiegazione:

hfqFSMsM.TcT2t./Q   implicit Q (=input) at the end
              ./Q   create all partitions of the input list 
                    (they are already sorted by number of cuts)
             t      remove the partition with zero splits
 f                  filter for partitions T, which satisfy:
          cT2          chop into pieces of length 2
        .T             transpose to get the pieces of each thieve
    SMsM               combine all pieces for each thieve and sort the results
  qF                   check if they got the same jewels
h                   print the first such partition

1

05AB1E , 14 byte

.œ¨ʒ2ôζε˜{}Ë}¤

Provalo online o verifica tutti i casi di test .

Spiegazione:

                # All partitions of the (implicit) input
                  #  i.e. [2,3,2,1,3,1]
                  #   → [[[2],[3],[2],[1],[3],[1]],[[2],[3],[2],[1],[3,1]],
                  #      ...,[[2,3,2,1,3,1]]]
  ¨               # Remove the last one
   ʒ        }     # Filter this list by:
    2ô            # Split it into parts of 2
                  #  i.e. [[2,3],[2],[1],[3,1]] → [[[2,3],[2]],[[1],[3,1]]]
                  #  i.e. [[2,3,2],[1,3],[1]] → [[[2,3,2],[1,3]],[[1]]]
      ζ           # Swap rows and columns (using space as filler if necessary)
                  #  i.e. [[[2,3],[2]],[[1],[3,1]]] → [[[2,3],[1]],[[2],[3,1]]]
                  #  i.e. [[[2,3,2],[1,3]],[[1]]] → [[[2,3,2],[1]],[[1,3]," "]]
       ε  }       # Map each inner list to:
        ˜         # Flatten the list
                  #  i.e. [[2,3],[1]] → [2,3,1]
                  #  i.e. [[1,3]," "] → [1,3," "]
         {        # Sort the list
                  #  i.e. [2,3,1] → [1,2,3]
                  #  i.e. [1,3," "] → [1,3," "]
           Ë      # Check if both sorted lists are equal
                  # (if not, remove them from the partitions)
             ¤    # After filtering, take the last one as result (and output implicitly)
                  #  i.e. [[[2],[3,2],[1,3],[1]],[[2,3],[2],[1],[3,1]]]
                  #   → [[2,3],[2],[1],[3,1]]
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.