Problème de division du collier

19

Contexte

J'ai été inspiré par la récente vidéo de 3Blue1Brown sur le problème de division du collier (ou comme il l'appelle, le problème du collier volé) et sa relation avec le théorème de Borsuk-Ulam .

Dans ce problème, deux voleurs ont volé un précieux collier composé de plusieurs types de bijoux. Il existe un nombre pair de chaque type de bijou et les voleurs souhaitent répartir chaque type de bijou de manière égale entre les deux. Le hic, c'est qu'ils doivent le faire en divisant le collier en un certain nombre de segments contigus et en répartissant les segments entre les deux.

Voici un exemple avec quatre types de bijoux dénotés S, E, Det R(pour le saphir, émeraude, diamant et rubis, respectivement). Disons que le collier est le suivant:

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

Il y a des 8saphirs, des 10émeraudes, des 4diamants et des 6rubis. Nous pouvons diviser le collier comme suit:

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

Ensuite, si nous donnons les premier, troisième et cinquième segments à un voleur et les deuxième et quatrième segments à l'autre voleur, chacun se retrouvera avec des 4saphirs, des 5émeraudes, des 2diamants et des 3rubis:

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

En utilisant l' 0indexation, ces coupes se produisent aux indices [1,2,9,22].

Objectif

Il s'avère qu'une telle division équitable peut toujours être effectuée en utilisant au plus des ncoupes, où nest le nombre de types de bijoux. Votre tâche consiste à écrire un programme ou une fonction complète qui prend un collier en entrée et génère une telle division minimale (le moins de coupes).

Contribution

L'entrée peut être dans n'importe quel format pratique. Le collier doit être une séquence de bijoux et rien de plus; par exemple une liste d'entiers, un dictionnaire avec des clés représentant les types de bijoux et les valeurs étant des listes d'indices. Vous pouvez éventuellement inclure la longueur du collier ou le nombre de types de bijoux distincts, mais vous ne devez pas prendre d'autre entrée.

Vous pouvez supposer que le collier d'entrée est valide. Vous n'avez pas besoin de gérer le cas où il y a un nombre impair de bijoux d'un type donné ou le collier est vide.

Production

Encore une fois, la sortie peut être dans n'importe quel format pratique; par exemple une liste de segments, une liste de positions de coupe, un dictionnaire avec des clés représentant les deux voleurs et des valeurs étant des listes de segments, etc. Les segments peuvent être représentés par leur index de départ, index de fin, liste d'index consécutifs, liste de bijoux, leurs longueurs, etc. Vous pouvez utiliser 0- ou 1- l'indexation. Si la commande n'est pas importante pour votre format, votre sortie peut être dans n'importe quel ordre. Voici la sortie ci-dessus dans plusieurs formats différents:

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

Notez que l'ordre est important dans la liste des segments (les segments alternent entre les voleurs) et la liste des longueurs (afin d'identifier les segments), mais pas dans la liste des coupes ou le dictionnaire. Edit: Greg Martin a souligné que ce ne seraient pas des sorties valides car une division équitable peut être obtenue en deux coupes

Cas de 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]]

Remarques

  1. Les failles standard sont interdites.
  2. C'est ; la réponse la plus courte (en octets) l'emporte.
ngenisis
la source
2
Le collier est-il circulaire?
Dennis
1
@Dennis Non, le collier est linéaire.
ngenisis
1
Pouvons-nous prendre l'entrée sous forme de lettres / jetons indiquant les différents types de bijoux, au lieu d'entiers?
Greg Martin
3
Si l'ordre des segments n'est pas modifié, les morceaux alternent entre theif A et theif B. En tant que tel, l'inclusion de ces informations dans la sortie est redondante. Pouvons-nous omettre l'indication theif si la réponse ne change pas l'ordre des bijoux? Avez-vous des cas de test?
Luke
2
Pour votre exemple [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], il semble que la sortie devrait être [[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]], car cela a moins de coupures que [[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]]. Suis-je bien comprendre la spécification?
Greg Martin

Réponses:

3

Brachylog , 13 octets

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

Essayez-le en ligne!

Remarque: le métaprédicat est plus récent que ce défi.

Explication

~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.

Les partitions sont énumérées dans l'ordre croissant du nombre de blocs, donc le résultat aura le moins de blocs possible.

Zgarb
la source
3

Gelée , 18 octets

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

Essayez-le en ligne!

Pas efficace - l'exemple a 28 joyaux qui ne fonctionneront pas sans ressources énormes car la première étape de cette implémentation serait de construire une liste des 2 27 partitions possibles.

Renvoie une liste de listes - les segments dans l'ordre de les répartir entre des voleurs alternatifs. (Concernant la sortie TIO: lorsqu'une liste n'a qu'un seul élément, l'impression implicite ne dérange pas avec les crochets, [])

Comment?

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)
Jonathan Allan
la source
3

Mathematica, 118 octets

Presque battre Jelly ... juste 1 off;)

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

Fonction pure prenant trois arguments: le collier, comme une liste de jetons tels que {A, A, A, A, B, C, D, B, C, D, B, B}; la longueur du collier; et le nombre de fois distinctes. Il renvoie une liste de sous-listes sous la forme {{A, A}, {-A, -A, -B, -C, -D, -B}, {C, D, B, B}}, où les jetons sans signe négatif vont à un voleur et les jetons avec signe négatif vont à l'autre voleur. (Bien qu'il s'agisse d'informations redondantes, l'algorithme conduit à cette représentation, et la suppression des signes négatifs coûterait plusieurs octets.)

Nous devons d'abord implémenter une fonction qui prend une liste et un ensemble de ndécoupes et renvoie la liste des n+1sous - listes obtenues en coupant la liste d'entrée à ces ndécoupes; l'opérateur d'infixe binaire ±est utilisé à cet effet et défini de manière récursive par l_±c_:=Append[-#±Most@c,#2]&@@l~TakeDrop~Last@c;l_±{}:={l};. En raison du signe négatif juste après Append, le résultat est que les sous-listes alternativement ont et n'ont pas de signes négatifs attachés à chaque jeton.

Ensuite, nous générons tous les ensembles de coupes possibles dont la longueur est au plus le nombre de types de bijoux, en utilisant Range@#2~Subsets~#3et en utilisant i=#;(i±#)&/@pour appliquer l' ±opérateur (avec la liste d'entrée des bijoux) à chacun de ces ensembles de coupes à tour de rôle.

Enfin, SelectFirst[...,Tr[Tr/@#]==0&]&choisit la première des divisions de collier résultantes qui est juste. Il le fait en additionnant littéralement tous les éléments dans toutes les sous-listes; Mathematica est assez sage pour annuler les copies positives et négatives de chaque jeton de manière évidente.

Greg Martin
la source
3

Pyth, 16 octets

hfqFSMsM.TcT2t./

Essayez-le en ligne: démonstration ou suite de tests

Explication:

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
Jakube
la source
1

05AB1E , 14 octets

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

Essayez-le en ligne ou vérifiez tous les cas de test .

Explication:

                # 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]]
Kevin Cruijssen
la source