【问题标题】:Bipartite Matching of Array数组的二分匹配
【发布时间】:2016-06-13 07:17:19
【问题描述】:

我有数组 A 和 B。我必须找到数组 B 的最大匹配,这样 B[i] 的每个索引都可以与 A[j] 的任何索引匹配当且仅当 A[j ]!=B[i] 和 A[j] 之前没有匹配。例如:

A = {1 2 3 4}
B = {2 2 3 4}
Maximum Matching is 4 A[0]=B[3] , A[1]=B[2] , A[2]=B[1], A[3]=B[0]

A = {1 1 2}
B  = {1 1 2}
Maximum Matching 2 A[0]=B[2] , B[1]=No Matching , A[2]=B[0]

我知道这是一个最大二分问题,但问题是 A=B 的长度。这将使我的二分解决方案超时。有没有更好的解决办法?

代码:

public static boolean is_match(int curr) {
    for(int i = 0; i < A.length; i++) {

        if(A[i] != curr && !V[i]) {

            V[i] = true;
            if(P[i] < 0 || is_match(P[i])) {
                P[i] = curr;
                return true;
            }
        }
    }
    return false;
}

我为每个 B 调用这个函数:

for(int i:B){
    V = new boolean[n]
    if(is_match(i)) match++;
}

如何改进我的解决方案?

【问题讨论】:

  • 您正在实施什么二分算法?匈牙利算法还是最大流量版本?

标签: algorithm graph


【解决方案1】:

这个问题可以可视化为最大流量问题。

因此,由于条件为A[j]!=B[i] and A[j] is not previously matched,因此知道A 中的索引i 是否匹配jB 中的kB[j] == B[k] 并不重要。

因此,不是将图表示为2*n 节点的二分图,而是每个节点表示数组 A 和 B 中的一个索引,我们可以将问题表示为一个流图,其中包含一个源节点、一个汇节点和列表表示 A 和 B 的唯一值的节点,以及节点 a(表示 A 中的 a 值)到源节点的容量是 A 中具有值 a 的索引数量。类似地,映射到下沉节点的节点b 的容量将等于B 中具有值为b 的索引的数量。从 A 到 B 的有效节点之间的容量是无穷大的。

例如,数组A = {1, 1, 2, 2}B = {1, 2, 2, 3, 3, 3, 3}

因此,我们创建了一个包含源节点和汇节点的流程图。

  • 另外,对于数组 A,我们创建了两个额外的节点,一个用于值 1,一个用于值 2。源节点将连接到这两个节点。

  • 对于节点 B,我们创建三个节点,一个用于值 1,一个用于值 2,一个用于值 3。

  • 现在,源节点将只连接到数组 A 中的节点,容量相等:节点 2 表示值 1(因为数组 A 中有两个 1),节点 2 表示值 2(有两个2 在数组 A) 中。

  • Sink 节点将仅连接到阵列 B 中的节点,容量为: 节点 1 代表值 1(数组 B 中只有一个 1);节点2代表值2(数组B中有两个2),节点4代表值3(数组B中有四个3)。

  • 从数组 A 到 B 的有效节点之间的连接将具有无限容量。

现在剩下的工作就是运行一个典型的最大流量算法。

【讨论】:

  • 我知道如何实现最大流算法,但我不明白如何将它们转换为最大流...我无法理解你答案的最后两行
  • @user5349222 示例已添加。
  • 对于最后一步Connection between array A and B will have infinity capacity. 如何保证不匹配A[i]=B[j]的边
  • 我还可以追踪哪个 A[i] 与哪个 B[j] 匹配吗...我想回溯会做到....
  • @user5349222 不好意思,连接只在有效节点之间,有点模糊。
【解决方案2】:

我认为您可以将原始算法调整为 O(n^2)。

对于 A 中的每个节点:(即此循​​环将重复 n 次)

  1. 第一次扫描,看看我们是否可以将此节点与 B 中的一个匹配。O(n)
  2. 如果不是,那么我们知道 B 中所有不匹配的节点与我们的 A 节点具有相同的值。将此值称为a。扫描所有以前的匹配项以查看是否有任何 A 节点 (!=a) 已与 B 节点 (!=a) 匹配。如果是这样,请更改前一个节点的映射,我们为新节点腾出空间。 O(n)

这是总体 O(n^2)。

只有当 B 中不等于 a 的所有节点都已经映射到 A 中等于 a 的节点时,第二遍才会找不到匹配项。这意味着等于 a 的节点太多,无法解决问题,而且问题不可能每个都满足。

【讨论】:

  • 您的解决方案也很简单,速度也很快...谢谢
【解决方案3】:

二分匹配问题可以通过所谓的Hungarian algorithm来解决,也可以建模为maximum flow problem;也许这些算法的实现更快。

作为流问题的建模工作如下; A 的项目构成左分区,B 的项目构成右分区。在分区之间,当且仅当可以匹配它们时,在节点之间创建容量为1 的边缘。将源节点放在最左边,将其连接到左侧分区的每个节点,其边缘容量为1;还将一个终端节点放在最右边,将其连接到右侧分区的每个节点,其容量为1。如果从源到终端的流量最大化,它将对应于通过选择中间这些具有非零流量值的边缘的最大匹配。

【讨论】:

  • 您能解释一下如何将其建模为最大流量问题吗?
猜你喜欢
  • 1970-01-01
  • 2010-10-27
  • 2012-08-06
  • 1970-01-01
  • 2020-09-05
  • 1970-01-01
  • 2020-10-14
相关资源
最近更新 更多