Beispiel #1
0
        private int[] edgeTo;             // edgeTo[v] = w if v-w is last edge on path to w

        /// <summary>
        /// Determines a maximum matching (and a minimum vertex cover)
        /// in a bipartite graph.</summary>
        /// <param name="G">the bipartite graph</param>
        /// <exception cref="ArgumentException">if <c>G</c> is not bipartite</exception>
        ///
        public BipartiteMatching(Graph G)
        {
            bipartition = new BipartiteX(G);
            if (!bipartition.IsBipartite)
            {
                throw new ArgumentException("graph is not bipartite");
            }

            numVertices = G.V;

            // initialize empty matching
            mate = new int[numVertices];
            for (int v = 0; v < numVertices; v++)
            {
                mate[v] = UNMATCHED;
            }

            // alternating path algorithm
            while (hasAugmentingPath(G))
            {
                // find one endpoint t in alternating path
                int t = -1;
                for (int v = 0; v < numVertices; v++)
                {
                    if (!IsMatched(v) && edgeTo[v] != -1)
                    {
                        t = v;
                        break;
                    }
                }

                // update the matching according to alternating path in edgeTo[] array
                for (int v = t; v != -1; v = edgeTo[edgeTo[v]])
                {
                    int w = edgeTo[v];
                    mate[v] = w;
                    mate[w] = v;
                }
                cardinality++;
            }

            // find min vertex cover from marked[] array
            inMinVertexCover = new bool[numVertices];
            for (int v = 0; v < numVertices; v++)
            {
                if (bipartition.Color(v) && !marked[v])
                {
                    inMinVertexCover[v] = true;
                }
                if (!bipartition.Color(v) && marked[v])
                {
                    inMinVertexCover[v] = true;
                }
            }
            Debug.Assert(certifySolution(G));
        }
Beispiel #2
0
 // is the edge v-w a forward edge not in the matching or a reverse edge in the matching?
 private bool isResidualGraphEdge(int v, int w)
 {
     if ((mate[v] != w) && bipartition.Color(v))
     {
         return(true);
     }
     if ((mate[v] == w) && !bipartition.Color(v))
     {
         return(true);
     }
     return(false);
 }
Beispiel #3
0
        // is there an augmenting path?
        // an alternating path is a path whose edges belong alternately to the matching and not to the matching
        // an augmenting path is an alternating path that starts and ends at unmatched vertices
        //
        // if so, upon termination edgeTo[] contains a parent-link representation of such a path
        // if not, upon terminatation marked[] specifies the subset of vertices reachable via an alternating
        // path from one side of the bipartition
        //
        // this implementation finds a shortest augmenting path (fewest number of edges), though there
        // is no particular advantage to do so here
        private bool hasAugmentingPath(Graph G)
        {
            marked = new bool[numVertices];

            edgeTo = new int[numVertices];
            for (int v = 0; v < numVertices; v++)
            {
                edgeTo[v] = -1;
            }

            // breadth-first search (starting from all unmatched vertices on one side of bipartition)
            LinkedQueue <int> queue = new LinkedQueue <int>();

            for (int v = 0; v < numVertices; v++)
            {
                if (bipartition.Color(v) && !IsMatched(v))
                {
                    queue.Enqueue(v);
                    marked[v] = true;
                }
            }

            // run BFS, stopping as soon as an alternating path is found
            while (!queue.IsEmpty)
            {
                int v = queue.Dequeue();
                foreach (int w in G.Adj(v))
                {
                    // either (1) forward edge not in matching or (2) backward edge in matching
                    if (isResidualGraphEdge(v, w))
                    {
                        if (!marked[w])
                        {
                            edgeTo[w] = v;
                            marked[w] = true;
                            if (!IsMatched(w))
                            {
                                return(true);
                            }
                            queue.Enqueue(w);
                        }
                    }
                }
            }

            return(false);
        }
Beispiel #4
0
 private static void BipartiteXReport(BipartiteX b)
 {
     if (b.IsBipartite)
     {
         Graph G = b.G;
         Console.WriteLine("Graph is bipartite");
         for (int v = 0; v < G.V; v++)
         {
             Console.WriteLine(v + ": " + b.Color(v));
         }
     }
     else
     {
         Console.Write("Graph has an odd-length cycle: ");
         foreach (int x in b.OddCycle())
         {
             Console.Write(x + " ");
         }
     }
     Console.WriteLine();
 }
Beispiel #5
0
        private int[] distTo;            // distTo[v] = number of edges on shortest path to v

        /// <summary>
        /// Determines a maximum matching (and a minimum vertex cover)
        /// in a bipartite graph.</summary>
        /// <param name="G">the bipartite graph</param>
        /// <exception cref="ArgumentException">if <c>G</c> is not bipartite</exception>
        ///
        public HopcroftKarp(Graph G)
        {
            bipartition = new BipartiteX(G);
            if (!bipartition.IsBipartite)
            {
                throw new ArgumentException("graph is not bipartite");
            }

            // initialize empty matching
            this.V = G.V;
            mate   = new int[V];
            for (int v = 0; v < V; v++)
            {
                mate[v] = UNMATCHED;
            }

            // the call to hasAugmentingPath() provides enough info to reconstruct level graph
            while (hasAugmentingPath(G))
            {
                // to be able to iterate over each adjacency list, keeping track of which
                // vertex in each adjacency list needs to be explored next
                IEnumerator <int>[] adj = new IEnumerator <int> [G.V];
                for (int v = 0; v < G.V; v++)
                {
                    adj[v] = G.Adj(v).GetEnumerator();
                }

                // for each unmatched vertex s on one side of bipartition
                for (int s = 0; s < V; s++)
                {
                    if (IsMatched(s) || !bipartition.Color(s))
                    {
                        continue;                                // or use distTo[s] == 0
                    }
                    // find augmenting path from s using nonrecursive DFS
                    LinkedStack <int> path = new LinkedStack <int>();
                    path.Push(s);
                    while (!path.IsEmpty)
                    {
                        int v = path.Peek();

                        // retreat, no more edges in level graph leaving v
                        if (!adj[v].MoveNext())
                        {
                            path.Pop();
                        }

                        // advance
                        else
                        {
                            // process edge v-w only if it is an edge in level graph
                            int w = adj[v].Current;
                            if (!isLevelGraphEdge(v, w))
                            {
                                continue;
                            }

                            // add w to augmenting path
                            path.Push(w);

                            // augmenting path found: update the matching
                            if (!IsMatched(w))
                            {
                                // Console.WriteLine("augmenting path: " + toString(path));

                                while (!path.IsEmpty)
                                {
                                    int x = path.Pop();
                                    int y = path.Pop();
                                    mate[x] = y;
                                    mate[y] = x;
                                }
                                cardinality++;
                            }
                        }
                    }
                }
            }

            // also find a min vertex cover
            inMinVertexCover = new bool[V];
            for (int v = 0; v < V; v++)
            {
                if (bipartition.Color(v) && !marked[v])
                {
                    inMinVertexCover[v] = true;
                }
                if (!bipartition.Color(v) && marked[v])
                {
                    inMinVertexCover[v] = true;
                }
            }

            Debug.Assert(certifySolution(G));
        }