项链劈开问题


19

背景

我受到3Blue1Brown最近关于项链劈裂问题(或他所说的是被盗的项链问题)及其与Borsuk-Ulam定理的关系的视频的启发。

在这个问题上,两个小偷偷走了一条有价值的项链,该项链由几种不同类型的珠宝组成。每种珠宝的数量都是偶数,盗贼希望在两种珠宝中平均分配每种珠宝。要注意的是,他们必须这样做,方法是将项链分成若干个连续的片段,并将片段分配在两个片段之间。

这里是表示4种宝石类型的示例SED,和R(对于蓝宝石,祖母绿,金刚石和红宝石,分别地)。假设项链如下:

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

8蓝宝石,10祖母绿,4钻石和6红宝石。我们可以如下分割项链:

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

然后,如果我们将第一,第三和第五部分分配给一个小偷,而将第二和第四部分分配给另一个小偷,则每一个都会以4蓝宝石,5祖母绿,2钻石和3红宝石:

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

使用 0 -indexing,这些削减发生在index处[1,2,9,22]

目标

事实证明,这样的公平划分总是可以使用最多 n切割,这n是珠宝类型的数量。您的任务是编写一个完整的程序或函数,该程序或函数将一条项链作为输入,并输出最小的此类分割(最少的切割次数)。

输入项

输入可以采用任何方便的格式。项链应该是一系列珠宝,仅此而已;例如整数列表,字典,字典中的键代表珠宝类型,而值代表索引列表。您可以选择包括项链的长度或不同珠宝类型的数量,但您不应输入任何其他信息。

您可以假设输入的项链有效。您无需处理给定类型的珠宝数量奇数或项链为空的情况。

输出量

同样,输出可以采用任何方便的格式。例如,片段列表,切割位置列表,带有表示两个小偷的键的字典以及片段列表的值等。片段可以通过其起始索引,结束索引,连续索引列表,珠宝列表,它们的长度等。您可以使用0-或1-索引。如果顺序对您的格式不重要,则您的输出可以按任何顺序排列。以下是上述输出的几种不同格式:

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

请注意,顺序在片段列表(小偷之间的片段交替)和长度列表(以识别片段)中很重要,但在剪切片段或字典中则不重要。 编辑:格雷格·马丁(Greg Martin)指出,这些将不是有效的输出,因为可以通过两次削减获得公平的划分

测试用例

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

笔记

  1. 禁止出现标准漏洞
  2. 这是;最短答案(以字节为单位)获胜。

2
项链是圆形的吗?
丹尼斯

1
@丹尼斯不,项链是线性的。
ngenisis

1
我们能否将输入作为表示不同珠宝类型的字母/令牌,而不是整数?
格雷格·马丁

3
如果段的顺序未更改,则段在theif A和theif B之间交替。因此,在输出中包括该信息是多余的。如果答案没有改变珠宝的顺序,我们可以省略theif指示吗?你有一些测试用例吗?
路加福音

2
对于您的示例[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],似乎应该是输出[[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]],因为它的剪切次数少于[[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]]。我是否正确理解规范?
格雷格·马丁

Answers:


3

Brachylog,13个字节

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

在线尝试!

注意:元谓词 比此挑战要新。

说明

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

分区按块数的升序进行枚举,因此结果将具有尽可能少的块。


3

果冻,18 字节

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

在线尝试!

效率不高-该示例包含28个珠宝,如果没有大量资源,它们将无法工作,因为此实现的第一步是构建2 27个可能分区的列表。

返回列表列表-这些段是为了将它们分配到另一个盗贼之间。(关于TIO的输出:当列表中只有一个项目时,隐式打印不会打扰括号,[]

怎么样?

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个字节

差点打败果冻……只差一分;)

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

具有三个参数的纯函数:项链,作为令牌列表,例如 {A, A, A, A, B, C, D, B, C, D, B, B};项链的长度;以及不同的珠宝次数。它以格式返回子列表的列表{{A, A}, {-A, -A, -B, -C, -D, -B}, {C, D, B, B}},其中没有负号的令牌转到一个小偷,而具有负号的令牌转到另一小偷。(虽然这是多余的信息,但算法会导致这种表示形式,而删除负号将花费几个字节。)

首先,我们必须实现一个函数,该函数需要一个列表和一组n剪切位置,并返回n+1通过在这些n剪切位置剪切输入列表而获得的子列表的列表。二进制中缀运算符±用于此目的,并通过进行递归定义l_±c_:=Append[-#±Most@c,#2]&@@l~TakeDrop~Last@c;l_±{}:={l};。由于Append紧随其后的负号,结果是子列表交替出现并且没有附加到每个令牌的负号。

然后,我们生成所有可能的切就地套,其长度最多为宝石类型的数量,使用Range@#2~Subsets~#3和使用i=#;(i±#)&/@±依次将运算符(带有珠宝的输入列表)应用于这些切位集合。

最后,SelectFirst[...,Tr[Tr/@#]==0&]&挑选出最合理的项链部门。它是通过字面加总所有子列表中的所有元素来实现的。Mathematica非常明智,可以以明显的方式取消每个令牌的正负副本。


3

Pyth,16个字节

hfqFSMsM.TcT2t./

在线尝试:演示测试套件

说明:

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 个字节

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

在线尝试验证所有测试用例

说明:

                # 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]]
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.