home *** CD-ROM | disk | FTP | other *** search
- /*******************************************************************************
- +
- + LEDA 2.1.1 11-15-1991
- +
- +
- + _mc_matching.c
- +
- +
- + Copyright (c) 1991 by Max-Planck-Institut fuer Informatik
- + Im Stadtwald, 6600 Saarbruecken, FRG
- + All rights reserved.
- +
- *******************************************************************************/
-
-
- /*******************************************************************************
- * *
- * MAX_CARD_MATCHING (maximum cardinality matching) *
- * *
- * Edmond's Algorithm (running time O(n*m*alpha(n)) ) *
- * *
- * S. Naeher (October 1991) *
- * *
- *******************************************************************************/
-
-
- #include <LEDA/graph_alg.h>
- #include <LEDA/node_partition.h>
-
- declare(node_array,node)
-
- static void find_path(list(node)& L, node_array(int)& label,
- node_array(node)& pred,
- node_array(node)& mate,
- node_array(edge)& bridge,
- node x, node y);
-
- enum LABEL {ODD, EVEN, UNREACHED};
-
- static graph* GP;
-
- static int cmp_degree(node& v,node& w) { return GP->indeg(v) - GP->indeg(w); }
-
-
- list(edge) MAX_CARD_MATCHING(graph& G, bool report_blossoms)
- {
-
- // input: directed graph G, we make it undirected (symmetric) by inserting
- // reversal edges
-
-
- list(edge) R;
-
- int strue = 0;
- bool done = false;
-
- node_array(int) label(G,UNREACHED);
- node_array(node) pred(G,nil);
- node_array(node) mate(G,nil);
- node_array(int) path1(G,0);
- node_array(int) path2(G,0);
- node_array(edge) bridge(G,nil);
- edge_array(edge) rev(G,nil);
-
- GP = &G;
-
-
- // make graph symmetric
-
- compute_correspondence(G,rev);
-
- edge e;
-
- list(edge) E = G.all_edges();
-
- forall(e,E)
- if (rev[e] == nil)
- { rev[e] = G.new_edge(target(e),source(e));
- R.append(rev[e]);
- }
-
- edge_array(edge) reversal(G);
-
- forall(e,E)
- { reversal[e] = rev[e];
- reversal[rev[e]] = e;
- }
-
- G.sort_nodes(cmp_degree); // sort nodes by degree
-
-
- forall_edges(e,G) // greedy
- { node v = source(e);
- node w = target(e);
-
- if (v != w && mate[v] == nil && mate[w] == nil)
- { mate[v] = w;
- mate[w] = v;
- }
- }
-
- while (! done) /* main loop */
- {
- list(node) Q;
- node v;
-
- node_partition base(G); // now base(v) = v for all nodes v
-
- done = true;
-
- forall_nodes(v,G)
- { pred[v] = nil;
-
- if (mate[v] == nil)
- { label[v] = EVEN;
- Q.append(v);
- }
- else label[v] = UNREACHED;
- }
-
- while (!Q.empty()) // search for augmenting path
- {
- node v = Q.pop();
- edge e;
-
- forall_adj_edges(e,v)
- {
- node w = G.target(e);
-
- if (v == w) continue; // ignore loops
-
- if (base(v) == base(w) || (label[w] == ODD && base(w) == w))
- continue; // do nothing
-
- if (label[w] == UNREACHED)
- { label[w] = ODD;
- pred[w] = v;
- label[mate[w]] = EVEN;
- Q.append(mate[w]);
- }
- else // base(v) != base(w) && (label[w] == EVEN || base(w) !=w)
- {
- node hv = base(v);
- node hw = base(w);
-
- strue++;
- path1[hv] = path2[hw] = strue;
-
- while ((path1[hw] != strue && path2[hv] != strue) &&
- (mate[hv] != nil || mate[hw] != nil) )
- {
- if (mate[hv] != nil)
- { hv = base(pred[mate[hv]]);
- path1[hv] = strue;
- }
-
- if (mate[hw] != nil)
- { hw = base(pred[mate[hw]]);
- path2[hw] = strue;
- }
- }
-
- if (path1[hw] == strue || path2[hv] == strue) // Shrink Blossom
- { node x;
- node y;
- node b = (path1[hw] == strue) ? hw : hv; // Base
-
- if (report_blossoms)
- { cout << "SHRINK BLOSSOM\n";
- cout << "bridge = ";
- G.print_edge(e);
- newline;
- cout << "base = ";
- G.print_node(b);
- newline;
- cout << "path1 = ";
- }
-
- x = base(v);
- while (x != b)
- {
-
- if (report_blossoms)
- { G.print_node(x);
- cout << " ";
- }
- base.union_blocks(x,b);
- base.set_inf(b,b);
-
- x = mate[x];
-
- if (report_blossoms)
- { G.print_node(x);
- cout << " ";
- }
- y = base(pred[x]);
- base.union_blocks(x,b);
- base.set_inf(b,b);
-
- Q.append(x);
-
- bridge[x] = e;
- x = y;
- }
-
- if (report_blossoms)
- { G.print_node(b);
- newline;
- cout << "path2 = ";
- }
-
- x = base(w);
- while (x != b)
- {
-
- if (report_blossoms)
- { G.print_node(x);
- cout << " ";
- }
- base.union_blocks(x,b);
- base.set_inf(b,b);
-
- x = mate[x];
-
- if (report_blossoms)
- { G.print_node(x);
- cout << " ";
- }
- y = base(pred[x]);
-
- base.union_blocks(x,b);
- base.set_inf(b,b);
-
- Q.append(x);
-
- bridge[x] = reversal[e];
-
- x = y;
- }
-
- if (report_blossoms)
- { G.print_node(b);
- newline;
- newline;
- }
- }
- else // augment path
- {
- list(node) P[2];
-
- find_path(P[0],label,pred,mate,bridge,v,hv);
- P[0].push(w);
- find_path(P[1],label,pred,mate,bridge,w,hw);
- P[1].pop();
-
- //cout << "augment path: ";
-
- for(int i=0; i<2; i++)
- while(! P[i].empty())
- { node a = P[i].pop();
- node b = P[i].pop();
- mate[a] = b;
- mate[b] = a;
- //G.print_node(a);
- //cout << " ";
- //G.print_node(b);
- //cout << " ";
- }
- //newline;
- //newline;
- Q.clear(); /* stop search (while Q not empty) */
- done = false; /* continue main loop */
- G.init_adj_iterator(v);
- break; /* forall_adj_edges(e,v) ... */
- }
-
- } // base(v) != base(w) && (label[w] == EVEN || base(w) !=w)
-
- } // for all adjacent edges
-
- } // while Q not empty
-
- } // while not done
-
-
- forall(e,R) G.del_edge(e); // restore graph (only original edges in result!)
-
- list(edge) result;
-
- forall_edges(e,G)
- { node v = source(e);
- node w = target(e);
- if ( v != w && mate[v] == w )
- { result.append(e);
- mate[v] = v;
- mate[w] = w;
- }
- }
-
-
- return result;
-
- }
-
-
-
- void find_path(list(node)& L, node_array(int)& label,
- node_array(node)& pred,
- node_array(node)& mate,
- node_array(edge)& bridge,
- node x, node y)
- {
- /* computes an even length alternating path from x to y begining with a
- matching edge (Tarjan: Data Structures and Network Algorithms, page 122)
- Preconditions:
- a) x and y are even or shrinked
- b) when x was made part of a blossom for the first time, y was a base
- and predecessor of the base of that blossom
- */
-
- if (x==y)
- { // [ x ]
- L.append(x);
- return;
- }
-
- if (label[x] == EVEN)
- { // [ x --> mate[x] --> path(pred[mate[x]],y) ]
- find_path(L,label,pred,mate,bridge,pred[mate[x]],y);
- L.push(mate[x]);
- L.push(x);
- return;
- }
-
- if (label[x] == ODD)
- { // [ x --> REV(path(source(bridge),mate[x])) --> path(target(bridge),y)) ]
- node v;
- list(node) L1;
- find_path(L,label,pred,mate,bridge,target(bridge[x]),y);
- find_path(L1,label,pred,mate,bridge,source(bridge[x]),mate[x]);
- forall(v,L1) L.push(v);
- L.push(x);
- return;
- }
- }
-
-