【问题标题】:Pool numbers in a set of numbers to match the size of another set汇集一组数字中的数字以匹配另一组的大小
【发布时间】:2013-01-21 12:15:24
【问题描述】:

我需要通过组合其中的数字来减小集合的大小。我需要所有可能的组合。 这里有两个例子可以说明我的情况。

1) Set1 有 4 个条目,Set2 有 2 个条目。所以我们需要在每种情况下组合两个数字。

Set1 = {70, 100, 50, 200}; Set2 = {"part1", "part2"}
All combinations I want to retrive should look like following:
"part1"        |"part2"
  70 + 100       |  50 + 200
  70 + 50        | 100 + 200
  70 + 200       |  50 + 100
 100 + 50       |  70 + 200
 100 + 200      |  50 +  70
  50 + 200       | 100 +  70
 50             |  70 + 100 + 200
 70             |  50 + 100 + 200
 100            |  50 +  70 + 200
 200            |  50 +  70 + 100  
 70 + 100 + 200 |  50
 50 + 100 + 200 |  70
 50 +  70 + 200 |  100
 50 +  70 + 100 |  200 

2) Set1 有 4 个条目,Set2 有 3 个条目。所以我们只需将两个数字组合一次。

Set1 = {70, 100, 50, 200}; Set2 = {"part1", "part2", "part3"}
All combinations I want to retrive should look like following:
"part1"   |"part2"     |"part3"
   70        | 100        |  50 + 200
   70        |  50        | 100 + 200
   70        | 200        |  50 + 100
   50        |  70        | 100 + 200 
   50        | 100        |  70 + 200
   50        | 200        |  70 + 100
 100       |  70        |  50 + 200
 100       | 200        |  50 +  70
 100       |  50        | 200 +  70
 200       |  70        |  50 + 100
 200       | 100        |  50 +  70
 200       |  50        |  70 + 100
   70        |  50 + 200  |  100
   70        | 100 + 200  |   50
   70        |  50 + 100  |  200
   50        | 100 + 200  |   70
   50        | 200 + 70   |  100
   50        |  70 + 100  |  200
 100       |  50 + 200  |   70
 100       |  50 +  70  |  200
 100       | 200 +  70  |   50
 200       |  50 + 100  |   70
 200       |  50 +  70  |  100
 200       |  70 + 100  |   50 
   50 + 200  | 100        |  70
 100 + 200 |  50        |  70
   50 + 100  | 200        |  70
 100 + 200 |  70        |  50
   70 + 200  | 100        |  50
   70 + 100  | 200        |  50
   50 + 200  |  70         | 100
   50 +  70  | 200         | 100
 200 +  70 |  50         | 100
   50 + 100  |  70         | 200
   50 +  70  | 100         | 200
   70 + 100  |  50         | 200

感谢您的帮助。我想不出任何词语来更好地解释我的担忧。但我很乐意回答任何问题。在你的帮助下,我也许能够证实我的问题。 虽然应用程序是用 C# 编写的,但我不一定需要源代码。我的问题是概念而不是实现。

提前致谢!

【问题讨论】:

  • 因此,给定一个集合Set1 和另一个大小为s 的集合Set2,您想将Set1 中的所有partitions 查找到s 部分中,其中1 部分的顺序很重要,2 部分中的元素顺序无关紧要,3 每个部分中的元素数量几乎相等.
  • 非常感谢您迄今为止的努力@Rawling。假设 12 正确。每个部分 (3) 中的元素数量不必几乎相等。我宁愿得到所有可能的组合。只能避免空分区。
  • 好的;在这种情况下,您在第一个示例中又少了 8 行 :)
  • 是的,你又是对的!我添加了缺失的可能性。
  • 您需要某种排序或任何顺序的可能输出?

标签: c# algorithm


【解决方案1】:

好的,所以这里的总体思路是

  • {0, 0, 0, 0} 开始 - 对于Set1 的每个元素,这都是零。
  • 0 代表Set2 中的第一项。因此,第一个数组是“Set1 中的所有内容都属于Set2 中的第一项”。
  • 返回与此对应的分区。
  • {0, 0, 0, 0} 增加到{0, 0, 0, 1}
  • 1 代表Set2 中的第二项。因此这个数组是“Set1 中的所有内容都属于Set2 中的第一项,除了最后一项,它属于Set2 中的第二项”。
  • 返回与此对应的分区。
  • {0, 0, 0, 1} 增加到{0, 0, 1, 0}(或{0, 0, 0, 2},如果Set2 中有两个以上的项目)。
  • 重复直到你点击{1, 1, 1, 1}(或{2, 2, 2, 2}等)并且不能再继续了。

然后您可以添加逻辑说“如果分区有任何 部分,请不要打扰它”。

我是这样实现的:

static IEnumerable<ILookup<T, U>> Pool<T, U>(T[] t, U[] u)
{
    // Start off with all zeroes.
    int[] indices = new int[u.Length];

    while (true)
    {
        // Build a Lookup from the array.
        var lookup = (Lookup<T,U>)indices
            .Select((ti, ui) => new { U = u[ui], T = t[ti] })
            .ToLookup(p => p.T, p => p.U);
        // Only return it if every part is non-empty.
        if (lookup.Count == t.Length)
            yield return lookup;

        // Increment to the next value.
        int toIncrement = u.Length - 1;
        while (++indices[toIncrement] == t.Length)
        {
            indices[toIncrement] = 0;

            // Stop when we can't increment further.
            if (toIncrement-- == 0)
                yield break;
        }
    }
}

你可以称之为

foreach (var q in Pool(
    new[] { "part1", "part2" },
    new[] { 70, 100, 50, 200 }))
{
    foreach (int i in q["part1"])
        Console.Write(i + " ");
    Console.Write("| ");
    foreach (var ii in q["part2"])
        Console.Write(ii + " ");
    Console.WriteLine();
}

请注意,由于我很懒,我已经创建了参数数组,但您可以将它们设为列表,或者将它们设为可枚举并在它们上调用 ToArray

【讨论】:

  • 不幸的是,我意识到,在某些情况下尝试所有组合是不可能的,因为有很多组合。 Set1 的计数通常超过 10(最多 35 个)。 Set2 往往有大约 8 个,但最多可以有 18 个条目。 @Rawling 你知道如何计算有希望的组合吗?例如。只有近乎平衡的套装?我的最终目标是找到一个与给定子集最相似的子集。我将相似度定义为每个位置的偏差之和。见:Fitting func
  • @Toby 这大大改变了你的问题的范围——如果我是你,我会把它作为一个新问题来问。确保包含一些“好”和“坏”结果的示例。
【解决方案2】:

你的问题的主要难点是:

如何获取给定集合的所有子集?

这是我的想法: 我想你的第一组不会超过 32 个元素。否则,结果将是相当巨大的。

然后,对于给定的集合MySet = { a, b, c, d, e },该集合的每个子集都可以用介于02^5 - 1 之间的值来描述。

如何?

使用位!好的,例如,数字 500101 二进制)表示 ac 包含在子集中。

所以要拥有一组给定N 元素的子集的整个集合。 只需从 0 迭代到 2^N-1 即可排除。

那么,如何创建其他部分(除了最后一个)?

只需获取第一组的补集并迭代其子集。

那么,最后一部分呢?

获取您之前部分的补充!

使用这种技术可能不必寻找前一个子集的补码,但它需要一些非标准的按位运算。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多