Grafalgo
Library of useful data structures and algorithms
|
00001 #include "fastEdmonds.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 fastEdmonds::fastEdmonds(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 // auxiliary data structures for reducing initialization overhead 00020 // in findpath 00021 searchNum = 0; 00022 latestSearch = new int[graf->n()+1]; // equals search number if reached 00023 nextEdge = new edge[graf->n()+1]; // next edge to search at u 00024 pending = new List(graf->n()); // used by findpath 00025 unmatched = new Dlist(graf->n()); // list of unmatched vertices 00026 00027 mSize = stepCount = blossomCount = pathInitTime = pathFindTime = 0; 00028 int t1, t2, t3; 00029 t1 = Util::getTime(); 00030 // Create initial maximal (not maximum) matching 00031 for (u = 1; u <= graf->n(); u++) { 00032 mEdge[u] = 0; mark[u] = false; latestSearch[u] = 0; 00033 nextEdge[u] = graf->firstAt(u); 00034 unmatched->addLast(u); 00035 } 00036 match->clear(); size = 0; 00037 for (u = 1; u <= graf->n(); u++) { 00038 if (mEdge[u] != 0) continue; 00039 for (e = graf->firstAt(u); e != 0; e = graf->nextAt(u,e)) { 00040 v = graf->mate(u,e); 00041 if (mEdge[v] == 0) { 00042 mEdge[u] = mEdge[v] = e; 00043 match->addLast(e); mSize++; 00044 unmatched->remove(u); 00045 unmatched->remove(v); 00046 break; 00047 } 00048 } 00049 } 00050 iSize = mSize; 00051 00052 t2 = Util::getTime(); 00053 imatchTime = (t2-t1); 00054 while((e = findpath()) != 0) { augment(e); mSize++; } 00055 size = mSize; 00056 t3 = Util::getTime(); 00057 rmatchTime = (t3-t2); 00058 00059 delete blossoms; delete augpath; delete [] origin; 00060 delete [] bridge; delete [] pEdge; delete [] mEdge; delete[] mark; 00061 } 00062 00063 // Modify the matching by augmenting along the path defined by 00064 // the list in the augpath data structure whose last element is e. 00065 void fastEdmonds::augment(edge e) { 00066 edge e1; 00067 while (true) { 00068 e1 = augpath->first(e); 00069 if (match->member(e1)) match->remove(e1); 00070 else { 00071 match->addLast(e1); 00072 mEdge[graf->left(e1)] = mEdge[graf->right(e1)] = e1; 00073 } 00074 if (e == augpath->first(e)) break; 00075 e = augpath->pop(e); 00076 } 00077 } 00078 00079 // If u and v are in the same tree, return their nearest common 00080 // ancestor in the current "condensed graph". To avoid excessive 00081 // search time, search upwards from both vertices in parallel, using 00082 // mark bits to identify the nca. Before returning, clear the mark 00083 // bits by traversing the paths a second time. The mark bits are 00084 // initialized in the constructor. 00085 vertex fastEdmonds::nca(vertex u, vertex v) { 00086 vertex x,px,y,py,result; 00087 00088 // first pass to find the nca 00089 x = u; px = (pEdge[x] != 0 ? graf->mate(x,pEdge[x]) : 0); 00090 y = v; py = (pEdge[y] != 0 ? graf->mate(y,pEdge[y]) : 0); 00091 while (true) { 00092 if (x == y) { result = x; break; } 00093 if (px == 0 && py == 0) { result = 0; break; } 00094 if (px != 0) { 00095 if (mark[x]) { result = x; break; } 00096 mark[x] = true; 00097 x = origin[blossoms->find(px)]; 00098 px = (pEdge[x] != 0 ? graf->mate(x,pEdge[x]) : 0); 00099 } 00100 if (py != 0) { 00101 if (mark[y]) { result = y; break; } 00102 mark[y] = true; 00103 y = origin[blossoms->find(py)]; 00104 py = (pEdge[y] != 0 ? graf->mate(y,pEdge[y]) : 0); 00105 } 00106 } 00107 // second pass to clear mark bits 00108 x = u, y = v; 00109 while (mark[x] || mark[y]) { 00110 mark[x] = mark[y] = false; 00111 px = (pEdge[x] != 0 ? graf->mate(x,pEdge[x]) : 0); 00112 py = (pEdge[y] != 0 ? graf->mate(y,pEdge[y]) : 0); 00113 x = (px == 0 ? x : origin[blossoms->find(px)]); 00114 y = (py == 0 ? y : origin[blossoms->find(py)]); 00115 } 00116 return result; 00117 } 00118 00119 // Find path joining a and b defined by parent pointers and bridges. 00120 // A is assumed to be a descendant of b, and the path to b from a 00121 // is assumed to pass through the matching edge incident to a. 00122 // Return path in the augpath data structure. 00123 edge fastEdmonds::path(vertex a, vertex b) { 00124 vertex pa, p2a, da; edge e, e1, e2; 00125 if (a == b) { return 0; } 00126 if (state[a] == even) { 00127 e1 = pEdge[a]; 00128 pa = graf->mate(a,e1); 00129 if (pa == b) { return e1; } 00130 e2 = pEdge[pa]; 00131 p2a = graf->mate(pa,e2); 00132 e = augpath->join(e1,e2); 00133 e = augpath->join(e,path(p2a,b)); 00134 return e; 00135 } else { 00136 e = bridge[a].e; da = bridge[a].v; 00137 e = augpath->join(augpath->reverse(path(da,a)),e); 00138 e = augpath->join(e,path(graf->mate(da,e),b)); 00139 return e; 00140 } 00141 } 00142 00143 // Search for an augmenting path in the graph graf. 00144 // On success, the path data structure will include a list 00145 // that forms the augmenting path. In this case, the last 00146 // edge in the list is returned as the function value. 00147 // On failure, returns 0. 00148 edge fastEdmonds::findpath() { 00149 vertex u,v,vp,w,wp,x,y; edge e; 00150 00151 int t1, t2, t3; 00152 t1 = Util::getTime(); 00153 00154 searchNum++; 00155 pending->clear(); 00156 vertex nextUnmatched = unmatched->first(); 00157 00158 t2 = Util::getTime(); 00159 pathInitTime += (t2-t1); 00160 while (true) { 00161 if (nextUnmatched != 0) { 00162 // initialize the next unmatched vertex and add 00163 // it to pending 00164 // doing it this way to reduce initialization overhead 00165 // when search ends fast 00166 pending->addLast(nextUnmatched); 00167 state[nextUnmatched] = even; 00168 pEdge[nextUnmatched] = 0; 00169 origin[nextUnmatched] = nextUnmatched; 00170 blossoms->clear(nextUnmatched); 00171 latestSearch[nextUnmatched] = searchNum; 00172 nextEdge[nextUnmatched] = graf->firstAt(nextUnmatched); 00173 nextUnmatched = unmatched->next(nextUnmatched); 00174 } 00175 if (pending->empty()) break; 00176 00177 v = pending->first(); e = nextEdge[v]; 00178 if (e == 0) { 00179 pending->removeFirst(); continue; 00180 } else { 00181 nextEdge[v] = graf->nextAt(v,e); 00182 } 00183 stepCount++; 00184 w = graf->mate(v,e); 00185 if (latestSearch[w] != searchNum && mEdge[w] != 0) { 00186 // w not yet reached in this search, so can't be 00187 // part of any blossom yet 00188 // extend the tree 00189 x = graf->mate(w,mEdge[w]); 00190 state[w] = odd; pEdge[w] = e; 00191 state[x] = even; pEdge[x] = mEdge[w]; 00192 origin[w] = w; origin[x] = x; 00193 latestSearch[w] = latestSearch[x] = searchNum; 00194 blossoms->clear(w); blossoms->clear(x); 00195 pending->addLast(x); 00196 nextEdge[x] = graf->firstAt(x); 00197 continue; 00198 } 00199 if (latestSearch[w] != searchNum) { 00200 // w is a tree root that hasn't been initialized yet 00201 // so, initialize and add to pending 00202 pending->addLast(w); 00203 state[w] = even; 00204 pEdge[w] = 0; 00205 origin[w] = w; 00206 blossoms->clear(w); 00207 latestSearch[w] = searchNum; 00208 nextEdge[w] = graf->firstAt(w); 00209 } 00210 vp = origin[blossoms->find(v)]; 00211 wp = origin[blossoms->find(w)]; 00212 if (vp == wp) continue; // skip internal edges in a blossom 00213 u = nca(vp,wp); 00214 if ((state[wp] == even || latestSearch[w] != searchNum) && 00215 u == 0) { 00216 // vp, wp are different trees - construct path & return 00217 x = vp; 00218 while (pEdge[x] != 0) { 00219 x = origin[blossoms->find( 00220 graf->mate(x,pEdge[x]) 00221 )]; 00222 } 00223 y = wp; 00224 while (pEdge[y] != 0) { 00225 y = origin[blossoms->find( 00226 graf->mate(y,pEdge[y]) 00227 )]; 00228 } 00229 e = augpath->join(augpath->reverse(path(v,x)),e); 00230 e = augpath->join(e,path(w,y)); 00231 // x and y will soon be matched 00232 unmatched->remove(x); unmatched->remove(y); 00233 t3 = Util::getTime(); 00234 pathFindTime += (t3-t2); 00235 return e; 00236 } else if (state[wp] == even) { 00237 // vp and wp are in same tree - collapse blossom 00238 blossomCount++; 00239 x = vp; 00240 while (x != u) { 00241 origin[blossoms->link( 00242 blossoms->find(x), 00243 blossoms->find(u))] = u; 00244 if (state[x] == odd) { 00245 bridge[x].e = e; bridge[x].v = v; 00246 if (!pending->member(x)) 00247 pending->addLast(x); 00248 } 00249 x = origin[blossoms->find( 00250 graf->mate(x,pEdge[x]))]; 00251 } 00252 x = wp; 00253 while (x != u) { 00254 origin[blossoms->link( 00255 blossoms->find(x), 00256 blossoms->find(u))] = u; 00257 if (state[x] == odd) { 00258 bridge[x].e = e; bridge[x].v = w; 00259 if (!pending->member(x)) 00260 pending->addLast(x); 00261 } 00262 x = origin[blossoms->find( 00263 graf->mate(x,pEdge[x]))]; 00264 } 00265 } 00266 } 00267 t3 = Util::getTime(); 00268 pathFindTime += (t3-t2); 00269 return 0; 00270 } 00271 00278 string& fastEdmonds::statString(bool verbose, string& s) { 00279 stringstream ss; 00280 if (verbose) { 00281 ss << "iSize=" << iSize << " "; 00282 ss << "mSize=" << mSize << " "; 00283 ss << "stepCount=" << stepCount << " "; 00284 ss << "blossomCount=" << blossomCount << " "; 00285 ss << "imatchTime=" << imatchTime << " "; 00286 ss << "rmatchTime=" << rmatchTime << " "; 00287 ss << "pathInitTime=" << pathInitTime << " "; 00288 ss << "pathFindTime=" << pathFindTime; 00289 } else { 00290 ss << iSize << " " << mSize << " "; 00291 ss << stepCount << " " << blossomCount << " "; 00292 ss << imatchTime << " "<< rmatchTime << " "; 00293 ss << pathInitTime << " " << pathFindTime; 00294 } 00295 s = ss.str(); 00296 return s; 00297 }