来自给定集合的所有可能的组合,但不重复集合的内部元素
本文关键字:集合 元素 内部 有可能 组合 | 更新日期: 2024-09-24 07:22:34
我有一些固定的整数集,每个整数集中的distict值都在增加,例如:
{1, 2, 4}, {1, 3}, {2, 4}, {2, 7}, {3, 6}, {5, 6}, {3, 5, 7}.
是否有任何算法或更好的C#代码,从给定的集合生成所有可能的组合,但不重复其内部整数,即
[{1, 2, 4}, {3, 6}] < all integers are unique
[{1, 2, 4}, {3, 5, 7}] < all integers are unique
[{1, 3}, {2, 4}, {5, 6}] <– all integers are unique.
等等
========================================
以下是输入数据的可能组织:
var set1 = new HashSet<int>() { 1, 2, 4 };
var set2 = new HashSet<int>() { 1, 3 };
var set3 = new HashSet<int>() { 2, 4 };
var set4 = new HashSet<int>() { 2, 7 };
var set5 = new HashSet<int>() { 3, 6 };
var set6 = new HashSet<int>() { 5, 6 };
var set7 = new HashSet<int>() { 3, 5, 7 };
var inputList = new List<HashSet<int>>();
inputList.Add(set1);
inputList.Add(set2);
inputList.Add(set3);
inputList.Add(set4);
inputList.Add(set5);
inputList.Add(set6);
inputList.Add(set7);
我需要从inputList中获得所有可能的集合列表(即组合)的列表(或集合),每个内部列表(组合)中都有唯一的整数。
此问题被标记为重复,并且已在此处找到答案:"生成所有可能的组合(8个答案)"。然而,在我看来,这本质上是一个不同的问题:
输入数据不是相同长度的两个数组,而是一个集合列表,每个集合中有不同数量的元素;
相同的元素可以存在于不同的集合中。
就我个人而言,我认为这是一个由两部分组成的问题:
- 在提供给您的号码列表中查找唯一的号码。要在C#中做到这一点,你可以使用hashset,也可以使用linq(我认为你想要它,因为你用linq标记了它)
- 形成这些数字的所有可能组合。这里已经回答了:从数字列表中获取所有可能的组合
编辑/更正
因此,深入研究这个问题,这里的目标是找到SETS的组合,而不是这些集合中的单个数字(正如我在上面最初指出的)。考虑到这一点,我会做以下事情:
- 创建一个正方形的二维布尔数组。每个布尔值表示该索引处的集合是否与其他索引处的集冲突。先填这个
- 使用标准组合数学(与上面提到的相同),但与布尔值列表的检查相结合以丢弃无效结果
我相信这确实应该奏效。我(可能)马上在这里创建一个例子!
代码
重要提示:这在任何意义上都不漂亮或优化,但它确实有效,它确实说明了解决这个问题的方法。一个简单的优化是将布尔数组传递到递归步骤中,在递归步骤中生成组合,并在生成冲突后立即停止递归。这将节省大量的时间和计算能力。话虽如此,我将把它留给读者练习。
只需将以下内容粘贴到一个新的控制台应用程序中,它就可以工作了。祝你好运!
static void Main(string[] args)
{
// create/read sets here
var integers = new List<int[]>(){new []{1,2,4}, new []{1,3}, new []{2, 4}, new []{2, 7}, new []{3, 6}, new []{5, 6}, new []{2, 5, 7}};
// allocate/populate booleans - loop may be able to be refined
var conflicts = new bool[integers.Count, integers.Count];
for (var idx = 0; idx < integers.Count; idx++)
for (var cmpIdx = 0; cmpIdx < integers.Count; cmpIdx++)
conflicts[idx, cmpIdx] = integers[idx].Any(x => integers[cmpIdx].Contains(x));
// find combinations (index combinations)
var combinations = GetCombinations(integers.Count);
// remove invalid entries
for (var idx = 0; idx < combinations.Count; idx++)
if (HasConflict(combinations[idx], conflicts))
combinations.RemoveAt(idx--);
// print out the final result
foreach (var combination in combinations) PrintCombination(combination, integers);
// pause
Console.ReadKey();
}
// get all combinatins
static List<Combination> GetCombinations(int TotalLists)
{
var result = new List<Combination>();
for (var combinationCount = 1; combinationCount <= TotalLists; combinationCount++)
result.AddRange(GetCombinations(TotalLists, combinationCount));
return result;
}
static List<Combination> GetCombinations(int TotalLists, int combinationCount)
{
return GetCombinations(TotalLists, combinationCount, 0, new List<int>());
}
// recursive combinatorics - loads of alternatives including linq cartesian coordinates
static List<Combination> GetCombinations(int TotalLists, int combinationCount, int minimumStart, List<int> currentList)
{
// stops endless recursion - forms final result
var result = new List<Combination>();
if (combinationCount <= 0)
{
if ((currentList ?? new List<int>()).Count > 0)
{
result.Add(new Combination() { sets = currentList });
return result;
}
return null;
}
for (var idx = minimumStart; idx <= TotalLists - combinationCount; idx++)
{
var nextList = new List<int>();
nextList.AddRange(currentList);
nextList.Add(idx);
var combinations = GetCombinations(TotalLists, combinationCount - 1, idx + 1, nextList);
if (combinations != null) result.AddRange(combinations);
}
return result;
}
// print the combination
static void PrintCombination(Combination value, List<int[]> sets)
{
StringBuilder serializedSets = new StringBuilder();
foreach (var idx in value.sets)
{
if (serializedSets.Length > 0) serializedSets.Append(", ");
else serializedSets.Append("{");
serializedSets.Append("{");
for (var setIdx = 0; setIdx < sets[idx].Length; setIdx++)
{
if (setIdx > 0) serializedSets.Append(", ");
serializedSets.Append(sets[idx][setIdx].ToString());
}
serializedSets.Append("}");
}
serializedSets.Append("}");
Console.WriteLine(serializedSets.ToString());
}
static bool HasConflict(Combination value, bool[,] conflicts)
{
for (var idx = 0; idx < value.sets.Count; idx++)
for (var cmpIdx = idx + 1; cmpIdx < value.sets.Count; cmpIdx++)
if (conflicts[value.sets[idx], value.sets[cmpIdx]]) return true;
return false;
}
// internal class to manage combinations
class Combination { public List<int> sets; }