【发布时间】:2017-05-27 05:33:29
【问题描述】:
如何有效地生成无重复的数字组合的集合,其中所有集合之间都有一定的独特数字。
*注意 : 范围编号总是从 0 开始。
示例:
范围编号(numbers[ ]) = 0,1,2,3,4,5,6,7 ==> 共 8 个数字 (n)。
组合 (k) = 5 个数字。
独特的数字 (nD) = 2 个数字。
结果:
0 1 2 3 4
0 1 2 5 6
0 1 3 5 7
0 1 4 6 7
0 2 3 6 7
0 2 4 5 7
0 3 4 5 6
有 7 种有效组合
如何组装:
到目前为止我取得了什么成就
我目前的解决方案效率很低(或者你可以称之为蛮力)。
* 首先 i 循环每个组合。 ==> k C n
* 然后我为有效组合创建一个临时文件。
* 然后,对于每个组合,我都会验证我的 temp,如果它有效,则将其存储在 temp 中,否则忽略它。
就是这样。
这是我在控制台应用程序中的代码:
class Program
{
static List<int[]> ValidCombinations;
static void Main()
{
ValidCombinations = new List<int[]>();
int[] numbers = Enumerable.Range(0, 8).ToArray();
int n = numbers.Length;
const int k = 5;
const int nD = 2;
int maxIntersect = k - nD;
int iCombination = 0;
int iValidCombination = 0;
int[] _temp = new int[k];
foreach (int[] c in FindCombinations(k, n))
{
// #Print out
for (int i = 0; i < n; i++)
{
if (c.Contains(i))
Console.Write(c[Array.IndexOf(c, i)] + " ");
else
Console.Write("_ ");
}
// Save to List
if (IsValidSet(c, maxIntersect))
{
_temp = new int[k];
for (int i = 0; i < c.Length; i++)
{
_temp[i] = c[i];
}
ValidCombinations.Add(_temp);
iValidCombination++;
Console.Write(" ### --> {0}", string.Join(" ", c));
}
Console.WriteLine();
iCombination++;
}
Console.WriteLine("\nTotal Combination = {0}", iCombination);
Console.WriteLine("Valid Combination Found = {0}", iValidCombination);
}
public static IEnumerable<int[]> FindCombosRec(int[] buffer, int done, int begin, int end)
{
for (int i = begin; i < end; i++)
{
buffer[done] = i;
if (done == buffer.Length - 1)
yield return buffer;
else
foreach (int[] child in FindCombosRec(buffer, done + 1, i + 1, end))
yield return child;
}
}
public static IEnumerable<int[]> FindCombinations(int m, int n)
{
return FindCombosRec(new int[m], 0, 0, n);
}
private static bool IsValidSet(int[] set, int maxIntersect)
{
foreach (var item in ValidCombinations)
{
if (set.Intersect(item).Count() > maxIntersect)
return false;
}
return true;
}
}
我得到了从here 生成组合的基本代码。
问题
这是可行的,但对于更大范围的数字,此解决方案将需要很长时间才能完成。我知道,因为涉及到组合算法,但必须有某种捷径或模式来简化它(我的小脑袋无法弄清楚)。
非常感谢。
【问题讨论】:
-
优化的第一步是将 n - k - nD 的第一个数字固定为始终存在(如果 n - k - nD
-
我上面的评论是错误的,让我重新表述为:优化的第一步是确定始终存在多少数字。在您的示例中,始终存在 0;在 n = 8、k = 5 和 nD = 1 的情况下,我们可以将 0、1、2 和 3 固定为始终存在。此外,确定行数肯定会很有用(在你的例子中是 7,在我的例子中是 4)。我感觉行数就是不定数的个数,但我还不能证明。
-
@FabianPijcke :这 3 个参数将始终存在,我无法修复该数字,因为它会影响它可能产生的最佳组合。也许我可以把它放到像这样的现实生活中..
-
@FabianPijcke : 抱歉在未完成时被点击.. 这是示例案例:"您是一位老师,即将给您的学生考试,如果您有 8 个问题并且你的每个学生应该得到 5 个问题,并且你想给学生之间 40% 的差异,那么这些问题的组合可以涵盖多少学生?” ..当然不是关于数字,而是组合本身。 (对不起,如果这种情况只会使情况更加混乱).
-
不,我明白了,尽管在您的真实示例中,教授不会介意某些学生之间的差异是否高于 40%,这只是恕我直言的下限。我说的不是参数之一,而是所有子集中存在的数字之一(0 从未出现在您的独特数字表中)...
标签: c# algorithm combinations