【问题标题】:(Ordered) Set Partitions in fixed-size Blocks(有序)在固定大小的块中设置分区
【发布时间】:2011-01-01 11:12:03
【问题描述】:

这是我想编写但无法编写的函数。即使你 不要/不能给出解决方案我将不胜感激提示。例如, 我知道有序表示之间存在相关性 整数和有序集分区的总和,但仅此一项并不能帮助我 找到解决方案。所以这里是我需要的功能的描述:


任务

创建一个高效的*函数

List<int[]> createOrderedPartitions(int n_1, int n_2,..., int n_k)

返回集合中所有集合部分的数组列表 {0,...,n_1+n_2+...+n_k-1} in number of arguments 大小的块(在此 订单)n_1,n_2,...,n_k(例如n_1=2, n_2=1, n_3=1 -&gt; ({0,1},{3},{2}),...)。

这是一个用法示例:

int[] partition = createOrderedPartitions(2,1,1).get(0);
partition[0]; // -> 0
partition[1]; // -> 1
partition[2]; // -> 3
partition[3]; // -> 2

注意列表中的元素个数是 (n_1+n_2+...+n_n choose n_1) * (n_2+n_3+...+n_n choose n_2) * ... * (n_k choose n_k)。此外,createOrderedPartitions(1,1,1) 将创建 {0,1,2} 的排列,因此在 列表。

*高效我的意思是你最初不应该创建一个更大的列表 像所有分区一样,然后过滤掉结果。你应该直接做。

额外要求

如果参数为 0,则将其视为不存在,例如 createOrderedPartitions(2,0,1,1) 应该产生与 createOrderedPartitions(2,1,1)。但至少有一个参数不能为 0。 当然,所有参数都必须 >= 0。

备注

提供的伪代码是准Java但解决方案的语言 没关系。事实上,只要解决方案相当普遍,并且可以 用其他语言复制是理想的。

实际上,List&lt;Tuple&lt;Set&gt;&gt; 的返回类型会更好(例如,当 在 Python 中创建这样的函数)。然而,那么争论有 不得忽略 0 值。 createOrderedPartitions(2,0,2) 然后 创建

[({0,1},{},{2,3}),({0,2},{},{1,3}),({0,3},{},{1,2}),({1,2},{},{0,3}),...]


背景

我需要这个功能来让我的主脑变体机器人更高效, 最重要的是代码更“漂亮”。看看filterCandidates my source code 中的函数。有不必要的 / 重复查询,因为我只是使用排列而不是 专门排序的分区。另外,我只是对如何写作感兴趣 这个函数。


我对(丑陋的)“解决方案”的想法

创建{0,...,n_1+...+n_k}的幂集,过滤掉大小的子集 n_1, n_2 等并创建 n 个子集的笛卡尔积。然而 这实际上不起作用,因为会有重复,例如 ({1,2},{1})...

首先选择x = {0,...,n_1+n_2+...+n_n-1}中的n_1,并把它们放在 第一组。然后选择n_2x without the n_1 chosen elements beforehand 等等。然后你会得到例如({0,2},{},{1,3},{4})。的 当然,必须创建每个可能的组合,所以({0,4},{},{1,3},{2}), 也是如此,等等。似乎很难实现,但有可能。


研究

我猜this 朝着我想要的方向前进,但是我不知道如何将其用于我的 具体场景。

http://rosettacode.org/wiki/Combinations

【问题讨论】:

  • 这可能是 math.stackexchange.com 的更多问题,因为从根本上说这是一个算法问题?或者甚至是 cstheory.stackexchange.com?

标签: language-agnostic math recursion combinatorics


【解决方案1】:

您知道,表达您的想法通常有助于提出解决方案。似乎潜意识刚刚开始处理任务并在找到解决方案时通知您。所以这是我在 Python 中的问题的解决方案:

from itertools import combinations

def partitions(*args):
    def helper(s, *args):
        if not args: return [[]]
        res = []
        for c in combinations(s, args[0]):
            s0 = [x for x in s if x not in c]
            for r in helper(s0, *args[1:]):
                res.append([c] + r)
        return res
    s = range(sum(args))
    return helper(s, *args)

print partitions(2, 0, 2)

输出是:

[[(0, 1), (), (2, 3)], [(0, 2), (), (1, 3)], [(0, 3), (), (1, 2)], [(1, 2), (), (0, 3)], [(1, 3), (), (0, 2)], [(2, 3), (), (0, 1)]]

将算法翻译成 Lua/Java 就足够了。这基本上是我的第二个想法。


算法

正如我在问题中已经提到的,基本思想如下:

首先选择集合s := {0,...,n_1+n_2+...+n_n-1}n_1元素并将它们放入 结果列表中第一个元组的第一组(例如,[({0,1,2},...,如果选择的元素是0,1,2)。然后选择集合s_0 := s without the n_1 chosen elements beforehandn_2元素,以此类推。一个这样的元组可能是({0,2},{},{1,3},{4})。的 当然,每个可能的组合都会被创建,所以({0,4},{},{1,3},{2}) 是另一个这样的元组等等。

实现

首先创建要使用的集合 (s = range(sum(args)))。然后这个集合和参数被传递给递归辅助函数helper

helper 执行以下操作之一: 如果处理了所有参数,则返回“某种空值”以停止递归。否则,遍历长度为args[0] 的传递集合s 的所有组合(helpers 之后的第一个参数)。在每次迭代中创建集合s0 := s without the elements in cc 中的元素是从s 中选择的元素),然后用于递归调用helper

所以helper 中的参数会发生什么,它们被一一处理。 helper 可能首先以helper([0,1,2,3], 2, 1, 1) 开头,然后在下一次调用中例如是helper([2,3], 1, 1),然后是helper([3], 1),最后是helper([])。当然,另一个“树路径”是helper([0,1,2,3], 2, 1, 1)helper([1,2], 1, 1)helper([2], 1)helper([])。创建所有这些“树路径”,从而生成所需的解决方案。

【讨论】:

  • 原来我根本不需要这个函数,因为有一种更简单的方法可以在策划者中过滤掉可能性。尽管如此,编写这个算法还是很有趣的。
猜你喜欢
  • 1970-01-01
  • 2013-12-13
  • 1970-01-01
  • 2010-09-25
  • 2014-05-20
  • 1970-01-01
  • 2010-11-13
  • 1970-01-01
  • 2023-04-09
相关资源
最近更新 更多