【问题标题】:How to find all partitions of a multiset (a set that allows duplicates)如何查找多重集的所有分区(允许重复的集)
【发布时间】:2018-12-05 05:33:17
【问题描述】:

给定一组可能包含重复的数字,找出它的所有分区。 (划分集合的所有可能方式。)

例如,多重集 {1, 1, 2} 有 4 个分区:

分区 1 = { {1}, {1}, {2} } 分区 2 = { {1}, {1, 2} } 分区 3 = { {1, 1}, {2} } 分区 4 = { {1, 1, 2} }

这是一个类似的问题How to find all partitions of a set,但在那个问题中,所有数字都是不同的。

设置分区的定义:https://en.wikipedia.org/wiki/Partition_of_a_set

多集定义:https://en.wikipedia.org/wiki/Multiset

我们将不胜感激以任何通用编程语言编写并带有一些解释的解决方案。


更新:

似乎很多人都对这个问题的问题感到困惑。它要求给定集合的所有可能子集。相反,它要求您找出划分给定数字集合的所有不同方法。

【问题讨论】:

  • 每个分区中的一个集合包含零个、一个或两个 1,以及零个或一个 2。然后可以递归地对剩余的较小集合进行分区。
  • @user3386109 你能写代码吗?
  • 顺便说一下,“多集的划分”并没有唯一的定义,因为有四种可能性:划分为一组集合;一组多组;多组集合;或多组多组。您的示例表明您正在寻找最后一个,但由于所有四种分区类型都有其用途,因此最好清楚。
  • 对不起,这是一个错误。

标签: algorithm set combinations partitioning


【解决方案1】:

嘿,我确实有一个 python 解决方案:

from sympy.utilities.iterables import multiset_partitions
from pi in multiset_partitions([1,1,3]):
    print pi

查看代码,你可以在 Knuth 的 AOCP 中找到算法,就在那里:http://www.cs.utsa.edu/~wagner/knuth/fasc3b.pdf

算法 M,第 39/40 页。

干杯:)

【讨论】:

    【解决方案2】:

    这是一个分区集问题。

    原始集合中的元素个数总是等于每个分区中元素个数的总和。

    可以使用回溯递归来解决。这个 C++ 程序可能很有用。

    void solve (set<vector<vector<int>>>& solution, vector<int> inputSet, 
    vector<vector<int>>& partitions, vector<int> partition, int n, int i) {
        int numberOfElements = 0;
        for (int i=0; i<partitions.size(); i++) {
            numberOfElements += partitions[i].size();
        }
        if (numberOfElements == n) {
            vector<vector<int>> newPartitions = partitions;
            for (int i=0; i<newPartitions.size(); i++) {
                sort (newPartitions[i].begin(), newPartitions[i].end());
            }
            sort(newPartitions.begin(), newPartitions.end());
            solution.insert(newPartitions);
            return;  
        }
        for (int j=i; j<n; j++) {
            partition.push_back(inputSet[j]);
            partitions.push_back(partition);
            vector<int> partitionNew;
            solve(solution, inputSet, partitions, partitionNew, n, j+1);
            partitions.pop_back();
        }
    }
    
    void permute (set<vector<vector<int>>>& solution, vector<int>& inputSet, int i, int n) {
        if (i == n) {
            vector<int> partition;
            vector<vector<int>> partitions;
            solve(solution, inputSet, partitions, partition, inputSet.size(), 0);
            return;
        }
        for (int j=i; j<=n; j++) {
            swap(inputSet[i], inputSet[j]);
            permute(solution, inputSet, i+1, n);
            swap(inputSet[i], inputSet[j]);
        }
    }
    

    这是工作示例:Generate all Partitions

    编辑:我误读了这个问题。我已经更新了答案。它现在生成所有可能的分区。

    【讨论】:

    • 要分区的集合是一个多重集,或包。幂集的概念可以扩展到多集,但多幂集的大小不是 2 的幂;相反,它是比每个独特元素的基数多一个的产物。 (如果所有元素都是唯一的,这就是集合的情况,那么该公式将简化为元素数量的 2 次方。但是,例如 {1, 1, 1, 2, 3, 3} 是 4*2*3 = 24。(此外,幂集只是偶尔用于枚举分区。)
    • @rici 说得好。这感觉与在给定素数分解的情况下找到所有因子非常相似。也许我在考虑乘法分区?
    • @joseph:是的,这是一个相关的问题。每个因子都是素因数分解的多重幂集的一个元素,但这对找到乘法分区集只有一点帮助。
    • 问题不是寻找 S 的所有子集,而是寻找划分数字集合的所有方法。因此,在示例中,有 4 种方法,每行是一个解决方案。
    • 11 ways分区{1, 1, 2, 3}。您的输出仅显示 8。
    猜你喜欢
    • 2020-05-14
    • 1970-01-01
    • 2015-09-29
    • 2012-03-16
    • 2013-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多