Grafalgo
Library of useful data structures and algorithms
|
00001 #include "edmonds.h" 00002 00003 using namespace grafalgo; 00004 00005 // Find a maximum size matching in the graph graf and 00006 // return it as a list of edges. 00007 edmonds::edmonds(Graph& graf1, Dlist& match1, int &size) 00008 : graf(&graf1), match(&match1) { 00009 vertex u, v; edge e; 00010 blossoms = new Partition(graf->n()); // set per blossom 00011 augpath = new RlistSet(graf->m()); // reversible list 00012 origin = new vertex[graf->n()+1]; // original vertex for each blossom 00013 bridge = new BridgePair[graf->n()+1];// edge that formed a blossom 00014 state = new stype[graf->n()+1]; // state used in path search 00015 pEdge = new edge[graf->n()+1]; // edge to parent in tree 00016 mEdge = new edge[graf->n()+1]; // incident matching edge (if any) 00017 mark = new bool[graf->n()+1]; // mark bits used by nca 00018 00019 mSize = stepCount = blossomCount = pathInitTime = pathFindTime = 0; 00020 int t1, t2, t3; 00021 t1 = Util::getTime(); 00022 // Create initial maximal (not maximum) matching 00023 for (u = 1; u <= graf->n(); u++) { 00024 mEdge[u] = 0; mark[u] = false; 00025 } 00026 match->clear(); size = 0; 00027 for (e = graf->first(); e != 0; e = graf->next(e)) { 00028 u = graf->left(e); v = graf->right(e); 00029 if (mEdge[u] == 0 && mEdge[v] == 0) { 00030 mEdge[u] = mEdge[v] = e; 00031 match->addLast(e); mSize++; 00032 } 00033 } 00034 iSize = mSize; 00035 00036 t2 = Util::getTime(); 00037 imatchTime = (t2-t1); 00038 while((e = findpath()) != 0) { augment(e); mSize++; } 00039 size = mSize; 00040 t3 = Util::getTime(); 00041 rmatchTime = (t3-t2); 00042 00043 delete blossoms; delete augpath; delete [] origin; 00044 delete [] bridge; delete [] pEdge; delete [] mEdge; delete[] mark; 00045 } 00046 00047 void edmonds::augment(edge e) { 00048 // Modify the matching by augmenting along the path defined by 00049 // the list in the augpath data structure whose last element is e. 00050 while (true) { 00051 edge e1 = augpath->first(e); 00052 if (match->member(e1)) match->remove(e1); 00053 else { 00054 match->addLast(e1); 00055 mEdge[graf->left(e1)] = mEdge[graf->right(e1)] = e1; 00056 } 00057 if (e == augpath->first(e)) break; 00058 e = augpath->pop(e); 00059 } 00060 } 00061 00062 // If u and v are in the same tree, return their nearest common 00063 // ancestor in the current "condensed graph". To avoid excessive 00064 // search time, search upwards from both vertices in parallel, using 00065 // mark bits to identify the nca. Before returning, clear the mark 00066 // bits by traversing the paths a second time. The mark bits are 00067 // initialized in the constructor. 00068 vertex edmonds::nca(vertex u, vertex v) { 00069 vertex x,px,y,py,result; 00070 00071 // first pass to find the nca 00072 x = u; px = (pEdge[x] != 0 ? graf->mate(x,pEdge[x]) : 0); 00073 y = v; py = (pEdge[y] != 0 ? graf->mate(y,pEdge[y]) : 0); 00074 while (true) { 00075 if (x == y) { result = x; break; } 00076 if (px == 0 && py == 0) { result = 0; break; } 00077 if (px != 0) { 00078 if (mark[x]) { result = x; break; } 00079 mark[x] = true; 00080 x = origin[blossoms->find(px)]; 00081 px = (pEdge[x] != 0 ? graf->mate(x,pEdge[x]) : 0); 00082 } 00083 if (py != 0) { 00084 if (mark[y]) { result = y; break; } 00085 mark[y] = true; 00086 y = origin[blossoms->find(py)]; 00087 py = (pEdge[y] != 0 ? graf->mate(y,pEdge[y]) : 0); 00088 } 00089 } 00090 // second pass to clear mark bits 00091 x = u, y = v; 00092 while (mark[x] || mark[y]) { 00093 mark[x] = mark[y] = false; 00094 px = (pEdge[x] != 0 ? graf->mate(x,pEdge[x]) : 0); 00095 py = (pEdge[y] != 0 ? graf->mate(y,pEdge[y]) : 0); 00096 x = (px == 0 ? x : origin[blossoms->find(px)]); 00097 y = (py == 0 ? y : origin[blossoms->find(py)]); 00098 } 00099 return result; 00100 } 00101 00102 edge edmonds::path(vertex a, vertex b) { 00103 // Find path joining a and b defined by parent pointers and bridges. 00104 // A is assumed to be a descendant of b, and the path to b from a 00105 // is assumed to pass through the matching edge incident to a. 00106 // Return path in the augpath data structure. 00107 vertex pa, p2a, da; edge e, e1, e2; 00108 if (a == b) return 0; 00109 if (state[a] == even) { 00110 e1 = pEdge[a]; 00111 pa = graf->mate(a,e1); 00112 if (pa == b) return e1; 00113 e2 = pEdge[pa]; 00114 p2a = graf->mate(pa,e2); 00115 e = augpath->join(e1,e2); 00116 e = augpath->join(e,path(p2a,b)); 00117 return e; 00118 } else { 00119 e = bridge[a].e; da = bridge[a].v; 00120 e = augpath->join(augpath->reverse(path(da,a)),e); 00121 e = augpath->join(e,path(graf->mate(da,e),b)); 00122 return e; 00123 } 00124 } 00125 00126 // Search for an augmenting path in the graph graf. 00127 // On success, the path data structure will include a list 00128 // that forms the augmenting path. In this case, the last 00129 // edge in the list is returned as the function value. 00130 // On failure, returns 0. 00131 edge edmonds::findpath() { 00132 vertex u,v,vp,w,wp,x,y; edge e, f; 00133 00134 int t1, t2, t3; 00135 t1 = Util::getTime(); 00136 00137 blossoms->clear(); 00138 for (u = 1; u <= graf->n(); u++) { 00139 state[u] = even; pEdge[u] = 0; origin[u] = u; 00140 } 00141 00142 for (e = match->first(); e != 0; e = match->next(e)) { 00143 u = graf->left(e); v = graf->right(e); 00144 state[u] = state[v] = unreached; 00145 } 00146 List q(graf->m()); // list of edges to be processed in main loop 00147 for (e = 1; e <= graf->m(); e++) { 00148 if (state[graf->left(e)] == even || 00149 state[graf->right(e)] == even) 00150 q.addLast(e); 00151 } 00152 00153 t2 = Util::getTime(); 00154 pathInitTime += (t2-t1); 00155 while (!q.empty()) { 00156 stepCount++; 00157 e = q.first(); q.removeFirst(); 00158 v = graf->left(e); vp = origin[blossoms->find(v)]; 00159 if (state[vp] != even) { 00160 v = graf->right(e); vp = origin[blossoms->find(v)]; 00161 } 00162 w = graf->mate(v,e); wp = origin[blossoms->find(w)]; 00163 if (vp == wp) continue; // skip internal edges in a blossom 00164 if (state[wp] == unreached) { 00165 // w is not contained in a blossom and is matched 00166 // so extend tree and add newly eligible edges to q 00167 x = graf->mate(w,mEdge[w]); 00168 state[w] = odd; pEdge[w] = e; 00169 state[x] = even; pEdge[x] = mEdge[w]; 00170 for (f = graf->firstAt(x); f != 0; 00171 f = graf->nextAt(x,f)) { 00172 if ((f != mEdge[x]) && !q.member(f)) 00173 q.addLast(f); 00174 } 00175 continue; 00176 } 00177 u = nca(vp,wp); 00178 if (state[wp] == even && u == 0) { 00179 // vp, wp are different trees - construct path & return 00180 x = vp; 00181 while (pEdge[x] != 0) { 00182 x = origin[blossoms->find( 00183 graf->mate(x,pEdge[x]))]; 00184 } 00185 y = wp; 00186 while (pEdge[y] != 0) { 00187 y = origin[blossoms->find( 00188 graf->mate(y,pEdge[y]))]; 00189 } 00190 e = augpath->join(augpath->reverse(path(v,x)),e); 00191 e = augpath->join(e,path(w,y)); 00192 t3 = Util::getTime(); 00193 pathFindTime += (t3-t2); 00194 return e; 00195 } else if (state[wp] == even) { 00196 // vp and wp are in same tree - collapse blossom 00197 blossomCount++; 00198 x = vp; 00199 while (x != u) { 00200 origin[blossoms->link( 00201 blossoms->find(x), 00202 blossoms->find(u))] = u; 00203 if (state[x] == odd) { 00204 bridge[x].e = e; bridge[x].v = v; 00205 for (f = graf->firstAt(x); f != 0; 00206 f = graf->nextAt(x,f)) 00207 if (!q.member(f)) q.addLast(f); 00208 } 00209 x = origin[blossoms->find( 00210 graf->mate(x,pEdge[x]))]; 00211 } 00212 x = wp; 00213 while (x != u) { 00214 origin[blossoms->link( 00215 blossoms->find(x), 00216 blossoms->find(u))] = u; 00217 if (state[x] == odd) { 00218 bridge[x].e = e; bridge[x].v = w; 00219 for (f = graf->firstAt(x); f != 0; 00220 f = graf->nextAt(x,f)) 00221 if (!q.member(f)) q.addLast(f); 00222 } 00223 x = origin[blossoms->find( 00224 graf->mate(x,pEdge[x]))]; 00225 } 00226 } 00227 } 00228 t3 = Util::getTime(); 00229 pathFindTime += (t3-t2); 00230 return 0; 00231 } 00232 00239 string& edmonds::statString(bool verbose, string& s) { 00240 stringstream ss; 00241 if (verbose) { 00242 ss << "iSize=" << iSize << " "; 00243 ss << "mSize=" << mSize << " "; 00244 ss << "stepCount=" << stepCount << " "; 00245 ss << "blossomCount=" << blossomCount << " "; 00246 ss << "imatchTime=" << imatchTime << " "; 00247 ss << "rmatchTime=" << rmatchTime << " "; 00248 ss << "pathInitTime=" << pathInitTime << " "; 00249 ss << "pathFindTime=" << pathFindTime; 00250 } else { 00251 ss << iSize << " " << mSize << " "; 00252 ss << stepCount << " " << blossomCount << " "; 00253 ss << imatchTime << " "<< rmatchTime << " "; 00254 ss << pathInitTime << " " << pathFindTime; 00255 } 00256 s = ss.str(); 00257 return s; 00258 }