c# - 如何高效生成总和在指定范围内的所有组合(在所有深度)

标签 c# algorithm recursion combinatorics

假设您有一组值 (1,1,1,12, 12,16)如何生成所有可能的组合(不重复),其总和在预定义范围[min,max]内。例如,以下是范围在 1317 之间的所有组合(所有深度):

1 12

1 1 12

1 1 1 12

16

1 16

这假设具有相同值的每个项目是无法区分的,因此最终输出中不会出现 1 12 三个结果。蛮力是可能的,但在项目数量很大的情况下,所有深度的组合数量都是天文数字。在上面的示例中,所有深度都有 (3 + 1) * (2 + 1) * (1 + 1) = 24 种组合。因此,总组合是任何给定值的项目数 + 1 的乘积。当然,我们可以从逻辑上丢弃大量其部分总和大于最大值的组合(例如集合 16 12 已经大于 17 的最大值,因此请跳过具有 1612 的任何组合> 在其中)。

我最初认为我可以将输入数组转换为两个数组,然后像里程表一样递增它们。但我完全陷入了这种提前崩溃的递归算法中。有什么建议吗?

{
    int uniqueValues = 3;
    int[] maxCounts = new int[uniqueValues];
    int[] values = new int[uniqueValues];

    // easy code to bin the data, just hardcoding for example
    maxCounts[0] = 3;
    values[0] = 1;
    maxCounts[1] = 2;
    values[1] = 12;
    maxCounts[2] = 1;
    values[2] = 16;

    GenerateCombinationsHelper(new List<int[]>(), 13, 17, 0, 0, maxCounts, new int[3], values);
}

private void GenerateCombinationsHelper(List<int[]> results, int min, int max, int currentValue, int index, int[] maxValues, int[] currentCombo, int[] values)
{
    if (index >= maxValues.Length)
    {
        return;
    }

    while (currentCombo[index] < maxValues[index])
    {
        currentValue += values[index];

        if (currentValue> max)
        {                   
            return;
        }

        currentCombo[index]++;

        if (currentValue< min)
        {                    
            GenerateCombinationsHelper(results, min, max, currentValue, index + 1, maxValues, currentCombo, values);
        }
        else
        {
            results.Add((int[])currentCombo.Clone());
        }
    }
}

编辑

整数值仅用于演示。它可以是任何具有某种数值的对象(intdoublefloat 等)

通常只有少数唯一值(大约 10 个),但总共可能有数千个项目。

最佳答案

将主调用切换到:

GenerateCombinationsHelper2(new List<int[]>(), 13, 17, 0, maxCounts, new int[3], values);

然后添加以下代码:

private void GenerateCombinationsHelper2(List<int[]> results, int min, int max, int index, int[] maxValues, int[] currentCombo, int[] values)
{
    int max_count = Math.Min((int)Math.Ceiling((double)max / values[index]), maxValues[index]);

    for(int count = 0; count <= max_count; count++)
    {
        currentCombo[index] = count;
        if(index < currentCombo.Length - 1)
        {
            GenerateCombinationsHelper2(results, min, max, index + 1, maxValues, currentCombo, values);
        }
        else
        {
            int sum = Sum(currentCombo, values);
            if(sum >= min && sum <= max)
            {
                int[] copy = new int[currentCombo.Length];
                Array.Copy(currentCombo, copy, copy.Length);
                results.Add(copy);
            }
        }
    }
}

private static int Sum(int[] combo, int[] values)
{
    int sum = 0;
    for(int i = 0; i < combo.Length; i++)
    {
        sum += combo[i] * values[i];
    }
    return sum;
}

它返回 5 个有效答案。

关于c# - 如何高效生成总和在指定范围内的所有组合(在所有深度),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19285438/

相关文章:

c# - SQL 服务器 : is there any performance penalty for wrapping a SELECT query in a transaction?

c# - .NET CookieContainer 帮助

algorithm - 将文本均匀地分成一定数量的行

javascript - 递归 xml 解析函数未按预期工作

javascript - 使用 Javascript 类函数进行 15 次递归后堆栈溢出

c# - 在不锁定 GUI 的情况下暂停方法的执行。 C#

c# - 在 RestSharp 中导入下一组图像

c++ - 围绕点拟合矩形

algorithm - linux diff -y 的算法是什么?

sql - 递归 PostgreSQL 函数失败并显示“游标已在使用”消息