📜  最大匹配的 Hopcroft–Karp 算法第 2 组(实施)

📅  最后修改于: 2022-05-13 01:57:54.431000             🧑  作者: Mango

最大匹配的 Hopcroft–Karp 算法第 2 组(实施)

我们强烈建议您参考以下帖子作为先决条件。
最大匹配的 Hopcroft–Karp 算法第 1 套(介绍)

在我们开始实施之前,有几件重要的事情需要注意。

  1. 我们需要找到一条增广路径(一条在匹配和不匹配边之间交替的路径,并且有自由顶点作为起点和终点)。
  2. 一旦我们找到交替路径,我们需要将找到的路径添加到现有的 Matching中。这里添加路径的意思是,使该路径上之前匹配的边为不匹配,之前不匹配的边为匹配。

这个想法是使用 BFS(广度优先搜索)来寻找增广路径。由于 BFS 是逐层遍历的,因此它用于将图划分为匹配边和不匹配边的层。添加了一个虚拟顶点 NIL,它连接到左侧的所有顶点和右侧的所有顶点。以下数组用于查找增广路径。到 NIL 的距离被初始化为 INF(无限)。如果我们从虚拟顶点开始并使用不同顶点的交替路径返回它,那么就有一条增广路径。

  1. pairU[]:大小为 m+1 的数组,其中 m 是二分图左侧的顶点数。如果 u 匹配,pairU[u] 将 u 对存储在右侧,否则存储 NIL。
  2. pairV[]:大小为 n+1 的数组,其中 n 是二分图右侧的顶点数。如果 v 匹配,pairV[v] 将 v 对存储在左侧,否则存储 NIL。
  3. dist[]:大小为 m+1 的数组,其中 m 是二分图左侧的顶点数。如果 u 不匹配,则 dist[u] 初始化为 0,否则初始化为 INF(无限)。 NIL 的 dist[] 也被初始化为 INF

一旦找到增广路径,就使用 DFS(深度优先搜索)将增广路径添加到当前匹配中。 DFS 只是遵循 BFS 设置的距离数组。如果在 BFS 中 v 与 u 相邻,它会填充 pairU[u] 和 pairV[v] 中的值。

下面是上述 Hopkroft Karp 算法的实现。

C++14
// C++ implementation of Hopcroft Karp algorithm for
// maximum matching
#include
using namespace std;
#define NIL 0
#define INF INT_MAX
 
// A class to represent Bipartite graph for Hopcroft
// Karp implementation
class BipGraph
{
    // m and n are number of vertices on left
    // and right sides of Bipartite Graph
    int m, n;
 
    // adj[u] stores adjacents of left side
    // vertex 'u'. The value of u ranges from 1 to m.
    // 0 is used for dummy vertex
    list *adj;
 
    // These are basically pointers to arrays needed
    // for hopcroftKarp()
    int *pairU, *pairV, *dist;
 
public:
    BipGraph(int m, int n); // Constructor
    void addEdge(int u, int v); // To add edge
 
    // Returns true if there is an augmenting path
    bool bfs();
 
    // Adds augmenting path if there is one beginning
    // with u
    bool dfs(int u);
 
    // Returns size of maximum matching
    int hopcroftKarp();
};
 
// Returns size of maximum matching
int BipGraph::hopcroftKarp()
{
    // pairU[u] stores pair of u in matching where u
    // is a vertex on left side of Bipartite Graph.
    // If u doesn't have any pair, then pairU[u] is NIL
    pairU = new int[m+1];
 
    // pairV[v] stores pair of v in matching. If v
    // doesn't have any pair, then pairU[v] is NIL
    pairV = new int[n+1];
 
    // dist[u] stores distance of left side vertices
    // dist[u] is one more than dist[u'] if u is next
    // to u'in augmenting path
    dist = new int[m+1];
 
    // Initialize NIL as pair of all vertices
    for (int u=0; u<=m; u++)
        pairU[u] = NIL;
    for (int v=0; v<=n; v++)
        pairV[v] = NIL;
 
    // Initialize result
    int result = 0;
 
    // Keep updating the result while there is an
    // augmenting path.
    while (bfs())
    {
        // Find a free vertex
        for (int u=1; u<=m; u++)
 
            // If current vertex is free and there is
            // an augmenting path from current vertex
            if (pairU[u]==NIL && dfs(u))
                result++;
    }
    return result;
}
 
// Returns true if there is an augmenting path, else returns
// false
bool BipGraph::bfs()
{
    queue Q; //an integer queue
 
    // First layer of vertices (set distance as 0)
    for (int u=1; u<=m; u++)
    {
        // If this is a free vertex, add it to queue
        if (pairU[u]==NIL)
        {
            // u is not matched
            dist[u] = 0;
            Q.push(u);
        }
 
        // Else set distance as infinite so that this vertex
        // is considered next time
        else dist[u] = INF;
    }
 
    // Initialize distance to NIL as infinite
    dist[NIL] = INF;
 
    // Q is going to contain vertices of left side only.
    while (!Q.empty())
    {
        // Dequeue a vertex
        int u = Q.front();
        Q.pop();
 
        // If this node is not NIL and can provide a shorter path to NIL
        if (dist[u] < dist[NIL])
        {
            // Get all adjacent vertices of the dequeued vertex u
            list::iterator i;
            for (i=adj[u].begin(); i!=adj[u].end(); ++i)
            {
                int v = *i;
 
                // If pair of v is not considered so far
                // (v, pairV[V]) is not yet explored edge.
                if (dist[pairV[v]] == INF)
                {
                    // Consider the pair and add it to queue
                    dist[pairV[v]] = dist[u] + 1;
                    Q.push(pairV[v]);
                }
            }
        }
    }
 
    // If we could come back to NIL using alternating path of distinct
    // vertices then there is an augmenting path
    return (dist[NIL] != INF);
}
 
// Returns true if there is an augmenting path beginning with free vertex u
bool BipGraph::dfs(int u)
{
    if (u != NIL)
    {
        list::iterator i;
        for (i=adj[u].begin(); i!=adj[u].end(); ++i)
        {
            // Adjacent to u
            int v = *i;
 
            // Follow the distances set by BFS
            if (dist[pairV[v]] == dist[u]+1)
            {
                // If dfs for pair of v also returns
                // true
                if (dfs(pairV[v]) == true)
                {
                    pairV[v] = u;
                    pairU[u] = v;
                    return true;
                }
            }
        }
 
        // If there is no augmenting path beginning with u.
        dist[u] = INF;
        return false;
    }
    return true;
}
 
// Constructor
BipGraph::BipGraph(int m, int n)
{
    this->m = m;
    this->n = n;
    adj = new list[m+1];
}
 
// To add edge from u to v and v to u
void BipGraph::addEdge(int u, int v)
{
    adj[u].push_back(v); // Add u to v’s list.
}
 
// Driver Program
int main()
{
    BipGraph g(4, 4);
    g.addEdge(1, 2);
    g.addEdge(1, 3);
    g.addEdge(2, 1);
    g.addEdge(3, 2);
    g.addEdge(4, 2);
    g.addEdge(4, 4);
 
    cout << "Size of maximum matching is " << g.hopcroftKarp();
 
    return 0;
}


Java
// Java implementation of Hopcroft Karp
// algorithm for maximum matching
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
 
class GFG{
 
static final int NIL = 0;
static final int INF = Integer.MAX_VALUE;
 
// A class to represent Bipartite graph
// for Hopcroft Karp implementation
static class BipGraph
{
     
    // m and n are number of vertices on left
    // and right sides of Bipartite Graph
    int m, n;
 
    // adj[u] stores adjacents of left side
    // vertex 'u'. The value of u ranges
    // from 1 to m. 0 is used for dummy vertex
    List[] adj;
 
    // These are basically pointers to arrays
    // needed for hopcroftKarp()
    int[] pairU, pairV, dist;
 
    // Returns size of maximum matching
    int hopcroftKarp()
    {
         
        // pairU[u] stores pair of u in matching where u
        // is a vertex on left side of Bipartite Graph.
        // If u doesn't have any pair, then pairU[u] is NIL
        pairU = new int[m + 1];
 
        // pairV[v] stores pair of v in matching. If v
        // doesn't have any pair, then pairU[v] is NIL
        pairV = new int[n + 1];
 
        // dist[u] stores distance of left side vertices
        // dist[u] is one more than dist[u'] if u is next
        // to u'in augmenting path
        dist = new int[m + 1];
 
        // Initialize NIL as pair of all vertices
        Arrays.fill(pairU, NIL);
        Arrays.fill(pairV, NIL);
 
        // Initialize result
        int result = 0;
 
        // Keep updating the result while
        // there is an augmenting path.
        while (bfs())
        {
             
            // Find a free vertex
            for(int u = 1; u <= m; u++)
             
                // If current vertex is free and there is
                // an augmenting path from current vertex
                if (pairU[u] == NIL && dfs(u))
                    result++;
        }
        return result;
    }
 
    // Returns true if there is an augmenting
    // path, else returns false
    boolean bfs()
    {
         
        // An integer queue
        Queue Q = new LinkedList<>();
 
        // First layer of vertices (set distance as 0)
        for(int u = 1; u <= m; u++)
        {
             
            // If this is a free vertex,
            // add it to queue
            if (pairU[u] == NIL)
            {
                 
                // u is not matched
                dist[u] = 0;
                Q.add(u);
            }
 
            // Else set distance as infinite
            // so that this vertex is
            // considered next time
            else
                dist[u] = INF;
        }
 
        // Initialize distance to
        // NIL as infinite
        dist[NIL] = INF;
 
        // Q is going to contain vertices
        // of left side only.
        while (!Q.isEmpty())
        {
             
            // Dequeue a vertex
            int u = Q.poll();
 
            // If this node is not NIL and
            // can provide a shorter path to NIL
            if (dist[u] < dist[NIL])
            {
                 
                // Get all adjacent vertices of
                // the dequeued vertex u
                for(int i : adj[u])
                {
                    int v = i;
 
                    // If pair of v is not considered
                    // so far (v, pairV[V]) is not yet
                    // explored edge.
                    if (dist[pairV[v]] == INF)
                    {
                         
                        // Consider the pair and add
                        // it to queue
                        dist[pairV[v]] = dist[u] + 1;
                        Q.add(pairV[v]);
                    }
                }
            }
        }
 
        // If we could come back to NIL using
        // alternating path of distinct vertices
        // then there is an augmenting path
        return (dist[NIL] != INF);
    }
 
    // Returns true if there is an augmenting
    // path beginning with free vertex u
    boolean dfs(int u)
    {
        if (u != NIL)
        {
            for(int i : adj[u])
            {
                 
                // Adjacent to u
                int v = i;
 
                // Follow the distances set by BFS
                if (dist[pairV[v]] == dist[u] + 1)
                {
                     
                    // If dfs for pair of v also returns
                    // true
                    if (dfs(pairV[v]) == true)
                    {
                        pairV[v] = u;
                        pairU[u] = v;
                        return true;
                    }
                }
            }
 
            // If there is no augmenting path
            // beginning with u.
            dist[u] = INF;
            return false;
        }
        return true;
    }
 
    // Constructor
    @SuppressWarnings("unchecked")
    public BipGraph(int m, int n)
    {
        this.m = m;
        this.n = n;
        adj = new ArrayList[m + 1];
        Arrays.fill(adj, new ArrayList<>());
    }
 
    // To add edge from u to v and v to u
    void addEdge(int u, int v)
    {
         
        // Add u to v’s list.
        adj[u].add(v);
    }
}
 
// Driver code
public static void main(String[] args)
{
     
    BipGraph g = new BipGraph(4, 4);
    g.addEdge(1, 2);
    g.addEdge(1, 3);
    g.addEdge(2, 1);
    g.addEdge(3, 2);
    g.addEdge(4, 2);
    g.addEdge(4, 4);
 
    System.out.println("Size of maximum matching is " +
                       g.hopcroftKarp());
}
}
 
// This code is contributed by sanjeev2552


输出:

Size of maximum matching is 4