(已订购)在固定大小的块中设置分区

时间:2011-01-01 11:12:03

标签: language-agnostic math recursion combinatorics

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


任务

创建高效的*功能

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

返回集合中所有设置部分的数组列表 {0,...,n_1+n_2+...+n_k-1} number of arguments块中的n_1,n_2,...,n_k(在此 订单)n_1=2, n_2=1, n_3=1 -> ({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}将创建 3! = 6的排列,因此会有createOrderedPartitions(2,0,1,1)个元素 列表。

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

额外要求

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

说明

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

实际上,更好的是createOrderedPartitions(2,0,2)的返回类型(例如,何时 在Python中创建这样的函数)。然而,那么论据有 不能忽略值0。然后会[({0,1},{},{2,3}),({0,2},{},{1,3}),({0,3},{},{1,2}),({1,2},{},{0,3}),...] 创建

filterCandidates


背景

我需要这个功能来使我的mastermind-variation bot更有效率 大部分代码都更“漂亮”。看看{0,...,n_1+...+n_k} my source code中的函数。没有必要 /重复查询,因为我只是使用排列而不是 特别订购的分区。另外,我只对如何写作感兴趣 这个功能。


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

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

首先选择x = {0,...,n_1+n_2+...+n_n-1}的{​​{1}}并将其放入。{1}} 第一集。然后选择n_2的{​​{1}},依此类推。然后你得到例如x without the n_1 chosen elements beforehand。的 当然,必须创建所有可能的组合({0,2},{},{1,3},{4}), 等等。似乎很难实现,但可能是可能的。


研究

我想this 按照我想要的方向前进但是我不知道如何将它用于我的方向 特定情况。

http://rosettacode.org/wiki/Combinations

1 个答案:

答案 0 :(得分: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就足够了。这基本上是我的第二个想法。


算法

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

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

实现

首先创建要使用的集合(({0,2},{},{1,3},{4}))。然后将此set和参数传递给递归辅助函数({0,4},{},{1,3},{2})

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

那么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)。创建所有这些“树路径”,从而生成所需的解决方案。