【问题标题】:Set partition with constraints in Python在 Python 中使用约束设置分区
【发布时间】:2015-06-25 03:26:03
【问题描述】:

我很难处理组分区问题。会有人流 请给我点灯?

让我简化一下我的问题。我想除以十个数字(即0, 1, ..., 9) 分成三组,每组有 (4, 3, 3) 个号码。条件是:

  1. 组内顺序无关紧要。例如,[(0, 1, 2, 3), (4, 5, 6), (7, 8, 9)] 将被视为与 [(3, 0, 1, 2), (5, 6, 4), (7, 8, 9)]。

  2. 我希望 (1, 2, 3) 始终在同一个组中,对于 (7, 8) 也是如此。

如何列出所有符合上述条件的可能分组方案?非常感谢!

我正在使用 Python 2.7。

【问题讨论】:

  • 您对 2. 的要求不清楚。什么决定了哪些数字应始终位于同一组中?
  • 当你忽略集合内的顺序时,并不是所有的排列,而是所有的集合分区:en.wikipedia.org/wiki/Partition_of_a_set
  • @DTing:我随意设置了约束。
  • 这更像是一道数学题,而不是编码题。
  • [{0,1,2,3},{4,5,6}{7,8,9}][{0,1,2,3},{7,8,9},{4,5,6}] 不同吗?

标签: python constraints partition


【解决方案1】:

如果我正确理解您的问题,这应该符合您的要求:

from copy import deepcopy

# slice into appropriate chunks
def slice_lst(size_tup, lst):
  for index, length in enumerate(size_tup):
    running_total = sum(size_tup[:index])
    yield lst[running_total:running_total+length]

# perform integer partition
def integer_partition(num):
  return {(x,) + y for x in range(1, num) for y in integer_partition(num-x)} | {(num,)}

# create all partitions given the starting list
def subsets(lst):
  for partition in integer_partition(len(lst)):
    yield list(slice_lst(partition, deepcopy(lst)))

# check that 1,2 and 3 are always contained within the same subset
def triplet_case(lst):
  bool_arr = [1 in lst, 2 in lst, 3 in lst]
  return all(bool_arr) or not any (bool_arr)

# check that 7 and 8 are always contained within the same subset
def duplet_case(lst):
  bool_arr = [7 in lst, 8 in lst]
  return all(bool_arr) or not any(bool_arr)

for subset in subsets([1,2,3,4,5,6,7,8,9]):
  if all([triplet_case(s) for s in subset]) and all([duplet_case(s) for s in subset]):
    print subset

如有任何问题,请随时提出后续问题!

【讨论】:

  • 感谢 EvenLisle。这与我的意图有点不同。首先,我需要大小为 4、3、3 的三个组。其次,您的代码似乎只对相邻的数字进行分组。例如,数字 9 永远不会与 1、2、3 保持在一组中。
【解决方案2】:
For comb in combination k=3 in (0,4,5,6,9), remaining a, b:
(g1+a, g2+b, comb)    (g1+b, g2+a, comb)
(g2+a+b, g3, g1)

For comb in combination k=4 in (0,4,5,6,9), remaining a:
(comb, g1, g2+a)

from itertools import combinations, permutations

def partition_generator():
  wildcards = (0,4,5,6,9)
  g1, g2 = (1,2,3), (7,8)
  for comb in combinations(wildcards, 3):
    unused = remaining(wildcards, comb)
    for r in permutations(unused):
      yield part(g1, g2, comb, r)
    yield part(g2, g1, comb, unused)
  for comb in combinations(wildcards, 4):
    yield part(comb, g1, g2, remaining(wildcards, comb))

def remaining(a, b):
  return [ x for x in a if x not in b ]

def part(x,y,z,remaining):
  q = list(remaining)
  while len(x) < 4:
    x = x + (q.pop(0),)
  if len(y) < 3:
    y = y + (q.pop(0),)
  if len(z) < 3:
    z = z + (q.pop(0),)
  return (x,y,z)

>>> for partition in partition_generator():
...   print(partition)
...
((1, 2, 3, 6), (7, 8, 9), (0, 4, 5))
((1, 2, 3, 9), (7, 8, 6), (0, 4, 5))
((7, 8, 6, 9), (1, 2, 3), (0, 4, 5))
((1, 2, 3, 5), (7, 8, 9), (0, 4, 6))
((1, 2, 3, 9), (7, 8, 5), (0, 4, 6))
((7, 8, 5, 9), (1, 2, 3), (0, 4, 6))
((1, 2, 3, 5), (7, 8, 6), (0, 4, 9))
((1, 2, 3, 6), (7, 8, 5), (0, 4, 9))
((7, 8, 5, 6), (1, 2, 3), (0, 4, 9))
((1, 2, 3, 4), (7, 8, 9), (0, 5, 6))
((1, 2, 3, 9), (7, 8, 4), (0, 5, 6))
((7, 8, 4, 9), (1, 2, 3), (0, 5, 6))
((1, 2, 3, 4), (7, 8, 6), (0, 5, 9))
((1, 2, 3, 6), (7, 8, 4), (0, 5, 9))
((7, 8, 4, 6), (1, 2, 3), (0, 5, 9))
((1, 2, 3, 4), (7, 8, 5), (0, 6, 9))
((1, 2, 3, 5), (7, 8, 4), (0, 6, 9))
((7, 8, 4, 5), (1, 2, 3), (0, 6, 9))
((1, 2, 3, 0), (7, 8, 9), (4, 5, 6))
((1, 2, 3, 9), (7, 8, 0), (4, 5, 6))
((7, 8, 0, 9), (1, 2, 3), (4, 5, 6))
((1, 2, 3, 0), (7, 8, 6), (4, 5, 9))
((1, 2, 3, 6), (7, 8, 0), (4, 5, 9))
((7, 8, 0, 6), (1, 2, 3), (4, 5, 9))
((1, 2, 3, 0), (7, 8, 5), (4, 6, 9))
((1, 2, 3, 5), (7, 8, 0), (4, 6, 9))
((7, 8, 0, 5), (1, 2, 3), (4, 6, 9))
((1, 2, 3, 0), (7, 8, 4), (5, 6, 9))
((1, 2, 3, 4), (7, 8, 0), (5, 6, 9))
((7, 8, 0, 4), (1, 2, 3), (5, 6, 9))
((0, 4, 5, 6), (1, 2, 3), (7, 8, 9))
((0, 4, 5, 9), (1, 2, 3), (7, 8, 6))
((0, 4, 6, 9), (1, 2, 3), (7, 8, 5))
((0, 5, 6, 9), (1, 2, 3), (7, 8, 4))
((4, 5, 6, 9), (1, 2, 3), (7, 8, 0))

【讨论】:

    【解决方案3】:

    所以你想分成 3 个大小为 4,3,3 的块,其中 (1,2,3) 在一个块中,(7,8) 在一个块中。

    这意味着1,2,3和7,8不能在同一个块中。

    让我们先忘记键盘,分析问题

    恕我直言,你应该分开 3 个案例:

    • 1,2,3 在大小为 4 的块中(案例 1)
    • 7,8 在大小为 4 的块中(案例 2)
    • 既不是 1,2,3 也不是 7,8,并且在大小为 4 的块中(案例 3)

    案例一

    • (0,4,5,6,9) 中的一个元素进入包含 (1, 2, 3) 的块中
    • 来自 (0,4,5,6,9) 的另一个元素进入包含 (7,8) 的块中

    总计:5*4 = 20 个不同的分区

    案例 2

    • 来自 (0,4,5,6,9) 的两个元素进入包含 (7,8) 的块中

    total : 5*4/2 = 10 个不同的分区(/2 因为你想要组合而不是排列)

    案例 3

    • (0,4,5,6,9) 中的一个元素进入包含 (7,8) 的块中

    总共:5 个不同的分区

    所以你知道你应该有 35 个不同的分区

    Python 代码:

    def gen():
        B1 = [1,2,3]
        B2 = [7,8]
        C = [x for x in range(10) if x not in B1 + B2 ]
        def gen1():
            for x in C:
                c = C[:]
                b1 = B1[:]
                b1.append(x)
                c.remove(x)
                for y in c:
                    c1 = c[:]
                    b2 = B2[:]
                    b2.append(y)
                    c1.remove(y)
                    yield(b1, b2, c1)
        def gen2():
            for i in range(len(C)-1):
                for j in range(i+1, len(C)):
                    b2 = B2 + [C[i], C[j]]
                    c = [C[k] for k in range(len(C)) if k not in (i,j)]
                    yield (B1, b2, c)
        def gen3():
            for x in C:
                b2 = B2[:]
                c = C[:]
                c.remove(x)
                b2.append(x)
                yield(B1, b2, c)
        for g in (gen1, gen2, gen3):
            for t in g():
                yield t
    

    你得到了正确的:

    >>> list(gen())
    [([1, 2, 3, 0], [7, 8, 4], [5, 6, 9]), ([1, 2, 3, 0], [7, 8, 5], [4, 6, 9]),
     ([1, 2, 3, 0], [7, 8, 6], [4, 5, 9]), ([1, 2, 3, 0], [7, 8, 9], [4, 5, 6]),
     ([1, 2, 3, 4], [7, 8, 0], [5, 6, 9]), ([1, 2, 3, 4], [7, 8, 5], [0, 6, 9]),
     ([1, 2, 3, 4], [7, 8, 6], [0, 5, 9]), ([1, 2, 3, 4], [7, 8, 9], [0, 5, 6]),
     ([1, 2, 3, 5], [7, 8, 0], [4, 6, 9]), ([1, 2, 3, 5], [7, 8, 4], [0, 6, 9]),
     ([1, 2, 3, 5], [7, 8, 6], [0, 4, 9]), ([1, 2, 3, 5], [7, 8, 9], [0, 4, 6]),
     ([1, 2, 3, 6], [7, 8, 0], [4, 5, 9]), ([1, 2, 3, 6], [7, 8, 4], [0, 5, 9]),
     ([1, 2, 3, 6], [7, 8, 5], [0, 4, 9]), ([1, 2, 3, 6], [7, 8, 9], [0, 4, 5]),
     ([1, 2, 3, 9], [7, 8, 0], [4, 5, 6]), ([1, 2, 3, 9], [7, 8, 4], [0, 5, 6]),
     ([1, 2, 3, 9], [7, 8, 5], [0, 4, 6]), ([1, 2, 3, 9], [7, 8, 6], [0, 4, 5]),
     ([1, 2, 3], [7, 8, 0, 4], [5, 6, 9]), ([1, 2, 3], [7, 8, 0, 5], [4, 6, 9]),
     ([1, 2, 3], [7, 8, 0, 6], [4, 5, 9]), ([1, 2, 3], [7, 8, 0, 9], [4, 5, 6]),
     ([1, 2, 3], [7, 8, 4, 5], [0, 6, 9]), ([1, 2, 3], [7, 8, 4, 6], [0, 5, 9]),
     ([1, 2, 3], [7, 8, 4, 9], [0, 5, 6]), ([1, 2, 3], [7, 8, 5, 6], [0, 4, 9]),
     ([1, 2, 3], [7, 8, 5, 9], [0, 4, 6]), ([1, 2, 3], [7, 8, 6, 9], [0, 4, 5]),
     ([1, 2, 3], [7, 8, 0], [4, 5, 6, 9]), ([1, 2, 3], [7, 8, 4], [0, 5, 6, 9]),
     ([1, 2, 3], [7, 8, 5], [0, 4, 6, 9]), ([1, 2, 3], [7, 8, 6], [0, 4, 5, 9]),
     ([1, 2, 3], [7, 8, 9], [0, 4, 5, 6])]
    

    (手动格式化以方便阅读...)

    【讨论】:

      猜你喜欢
      • 2014-02-24
      • 2022-01-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-22
      相关资源
      最近更新 更多