產生所有集合分區
組合數學中的基本問題之一是尋找給定集合的所有分區。集合劃分將集合劃分為非空的不相交子集,稱為區塊或部分。
在這個問題中,我們尋求一種方法來列舉具有不同元素的集合的所有劃分。考慮集合 {1, 2, 3}。其分區為:
分區演算法
任務可以分解為兩個子問題:分割成兩部分以及將一部分分割成多個
兩部分分區
對於n 元素集,可以透過將每個元素表示為n- 中的一個位元來產生所有兩部分分區位元模式。 0 位元表示放置在第一部分中,1 位元表示放置在第二部分。為了避免交換部件時出現重複結果,我們始終將第一個元素指派給第一個部件。這留下 (2^(n-1))-1 唯一的兩部分模式。
遞歸分區
使用兩部分分區技術,我們可以遞歸構造所有分區。
C# 實作
以下 C# 實作採用遞歸分區演算法:
using System; using System.Collections.Generic; using System.Linq; namespace PartitionTest { public static class Partitioning { public static IEnumerable<T[][]> GetAllPartitions<T>(T[] elements) { return GetAllPartitions(new T[][]{}, elements); } private static IEnumerable<T[][]> GetAllPartitions<T>(T[][] fixedParts, T[] suffixElements) { // Trivial partition: fixed parts followed by all suffix elements as a single block yield return fixedParts.Concat(new[] { suffixElements }).ToArray(); // Two-group-partitions of suffix elements and their recursive sub-partitions var suffixPartitions = GetTuplePartitions(suffixElements); foreach (Tuple<T[], T[]> suffixPartition in suffixPartitions) { var subPartitions = GetAllPartitions( fixedParts.Concat(new[] { suffixPartition.Item1 }).ToArray(), suffixPartition.Item2); foreach (var subPartition in subPartitions) { yield return subPartition; } } } private static IEnumerable<Tuple<T[], T[]>> GetTuplePartitions<T>(T[] elements) { if (elements.Length < 2) yield break; for (int pattern = 1; pattern < 1 << (elements.Length - 1); pattern++) { List<T>[] resultSets = { new List<T> { elements[0] }, new List<T>() }; for (int index = 1; index < elements.Length; index++) { resultSets[(pattern >> (index - 1)) & 1].Add(elements[index]); } yield return Tuple.Create(resultSets[0].ToArray(), resultSets[1].ToArray()); } } } }
以上是我們如何產生給定集合的所有集合分區?的詳細內容。更多資訊請關注PHP中文網其他相關文章!