【问题标题】:Select optimal pairings of elements选择元素的最佳配对
【发布时间】:2016-12-04 18:09:21
【问题描述】:

我有以下问题,例如: 给定一个带有符号的桶
1 1 2 3 3 4
以及创建配对的食谱书,例如:
121324
从桶中选择最佳配对,在桶中留下尽可能少的符号。因此,使用最佳配对上方的示例值将是:
13 13 24 这将使用给定的所有符号。
天真地从桶中挑选可能会导致以下结果:
12 13 使 34 不匹配。 34 无法匹配,因为该书不包含该特定连接的配方

注意事项:
真正的问题平均在于:桶中的 500 个元素,大约 30 种符号。

我们已经尝试使用蛮力算法来实现该解决方案,但恐怕连我们的孙子都无法活到看到结果:)。

食谱书的大小没有限制,它甚至可以在桶中拥有所有可能的东西。不允许两次由相同元素组成的对。

完全清空桶不需要答案。它只是从桶中取出最多的对。把一些留在桶里没关系。最好寻找最佳解决方案,但接近的近似值也足够了。

我将不胜感激提出/暗示解决问题的算法的答案。

示例:
斗:
1 1 2 2 2 2 3 3 3 4 5 6 7 8 8
食谱书:
12 34 15 68
最佳结果(可能之一):
{1 2} {1 2} {3 4} {6 8}
剩:
2233578

【问题讨论】:

  • 12 13 示例中,配对34 有什么问题?
  • 我已经更新了答案。配方书中没有 34 连接。我们只能根据预先给定的配方列表进行连接。
  • 我相信你可以使用线性代数技术走得很远,但我并不完全精通细节。您应该从“考虑问题”开始,即“我应该为每个符号使用多少个配对?”。因此,在上面的示例中,1 符号可以表示为 x+y=2 其中 2 是 1 符号的数量,xy 分别是 1213 的数量.接下来,您将拥有x+z=1y=2z=1,您显然可以从中解决x=0 以获得所需的结果。当不存在解决方案并且您需要一个近似值时,将使用线性代数。
  • @Amit 我无法理解您的解释。您能否为我在问题中的第二个示例发布示例解决方案?
  • 在将第二个示例表示为一组方程方面,我们表示a: 12, b: 34, c: 15, d: 68,方程为:a+c=2a=4b=3b=1c=1d=1 (nothing)=1d=2。现在,显然这组方程没有解,所以你需要一个近似值,但你可以看到你的答案是如何拟合的,以及每对中的 1 个 (a=b=c=d=1)。

标签: algorithm matching


【解决方案1】:

这个问题本质上是maximum matching problem 的一个小扭曲,即允许您拥有重复的对象。假设您有一个最大匹配的求解器,这是解决此问题的一种方法:

  1. 为输入列表中的每个数字创建一个节点。

  2. 对于每个配方,对于与该配方匹配的每对数字,在这些数字的节点之间添加一条边。

  3. 运行最大匹配算法并返回以这种方式报告的对。

您可以使用大量现成的最大匹配算法,如果您需要自己编写一个,请考虑使用Edmonds' Blossom Algorithm,与其他方法相比,它相当高效且编写起来更简单。

【讨论】:

  • 感谢您提出问题!一定会读一读,并报告结果。
  • 感谢您的回答,@templatetypedef,感谢您的回答,我刚刚搜索了最大匹配问题,发现 boost 中有一个实现并将其用于我的目的。 boost.org/doc/libs/1_61_0/libs/graph/example/…
【解决方案2】:

首先生成所有可能的符号对并将它们与每个符号的索引一起存储,因此如果您有 n 个符号,则将生成 n*(n+1)/2 对(最大情况下 n=500 然后将生成 125250 对)。

例如:带有符号 1 1 3 的桶 然后将生成对是 (11,1,2)(13,1,3)(13,2,3)。 一般格式( a[i]a[j], i, j )。

现在让我们循环生成的对并删除食谱书中不存在的对,所以现在我们最多有 30 个对。

接下来让我们构建一个图,使得节点是我们生成的对,并且如果 2 对的索引不同(在我们的对上使用 2 个嵌套循环),则每个 2 个节点都是连接的。

最后我们可以执行 BFSDFS 并找到所有生成的图之间最长的图,这就是我们问题的答案。

如果您想要 c++/Java 实现,请不要犹豫。

【讨论】:

  • 连接两个节点时一切正常,但在第三个节点上,我们可能会从第一个节点取一个已经配对的符号。
  • 我不太明白你的意思,但如果你问的是对冗余,使用 2 个嵌套循环很容易解决,这样内循环严格高于根循环 i (1 ..n) , j (i+1,n) ,这将消除冗余。
  • 这不是蛮力的做法吗?在我的第二个示例中,我的蛮力算法总共执行了 378 个组合。我的代码(如果你想看一下..)可以在这里找到:volatileread.com/utilitylibrary/snippetcompiler?id=67897 Function DoIt has main implementation
  • 这种改进的蛮力,我提到max case会创建125250对,在c++/java下这样的程序可以在1s下运行。
  • 您的解决方案非常接近:)。但是我没有使用 BFS/DFS 搜索,而是使用了最大匹配示例
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-08
  • 2014-11-12
  • 2015-10-31
  • 2010-10-27
  • 1970-01-01
相关资源
最近更新 更多