Grafalgo
Library of useful data structures and algorithms
|
00001 #include "cycRed.h" 00002 00003 using namespace grafalgo; 00004 00005 // Find minimum cost, maximum flow in wfg using 00006 // the cycle reduction algorithm. 00007 cycRed::cycRed(Wflograph& wfg1, flow& floVal, cost& floCost) : wfg(&wfg1) { 00008 vertex u; 00009 00010 pEdge = new edge[wfg->n()+1]; 00011 mark = new int[wfg->n()+1]; 00012 00013 dinicDtrees x(*wfg,floVal); 00014 00015 while ((u = findCyc()) != 0) augment(u); 00016 00017 floCost = 0; 00018 for (edge e = 1; e <= wfg->m(); e++) { 00019 vertex u = wfg->tail(e); 00020 floCost += wfg->f(u,e)*wfg->cost(u,e); 00021 } 00022 } 00023 00024 void cycRed::augment(vertex z) { 00025 // Add flow to cycle defined by pEdge pointers that includes z. 00026 vertex u, v; edge e; flow f; 00027 00028 // determine residual capacity of cycle 00029 f = Util::BIGINT32; 00030 u = z; e = pEdge[u]; 00031 do { 00032 v = wfg->mate(u,e); 00033 f = min(f,wfg->res(v,e)); 00034 u = v; e = pEdge[u]; 00035 } while (u != z); 00036 00037 // add flow to saturate cycle 00038 u = z; e = pEdge[u]; 00039 do { 00040 v = wfg->mate(u,e); 00041 wfg->addFlow(v,e,f); 00042 u = v; e = pEdge[u]; 00043 } while (u != z); 00044 } 00045 00046 vertex cycRed::findCyc() { 00047 // Find a negative cost cycle in the residual graph. 00048 // If a cycle is found, return some vertex on the cycle, 00049 // else 0. In the case there is a cycle, you can traverse 00050 // the cycle by following pEdge pointers from the returned vertex. 00051 00052 vertex u,v,last; edge e; 00053 int c[wfg->n()+1]; 00054 List q(wfg->n()); 00055 00056 for (u = 1; u <= wfg->n(); u++) { 00057 pEdge[u] = 0; c[u] = 0; q.addLast(u); 00058 } 00059 00060 last = q.last(); // each pass completes when last removed from q 00061 while (!q.empty()) { 00062 u = q.first(); q.removeFirst(); 00063 for (e = wfg->firstAt(u); e != 0; e = wfg->nextAt(u,e)) { 00064 if (wfg->res(u,e) == 0) continue; 00065 v = wfg->mate(u,e); 00066 if (c[v] > c[u] + wfg->cost(u,e)) { 00067 pEdge[v] = e; 00068 c[v] = c[u] + wfg->cost(u,e); 00069 if (!q.member(v)) q.addLast(v); 00070 } 00071 } 00072 00073 if (u == last) { 00074 v = cycleCheck(); 00075 if (v != 0) return v; 00076 last = q.last(); 00077 } 00078 } 00079 return 0; 00080 } 00081 00082 vertex cycRed::cycleCheck() { 00083 // If there is a cycle defined by the pEdge pointers, return 00084 // some vertex on the cycle, else null. 00085 vertex u,v; edge e; int cm; 00086 00087 for (u = 1; u <= wfg->n(); u++) { mark[u] = 0; } 00088 u = 1; cm = 1; 00089 while(u <= wfg->n()) { 00090 // follow parent pointers from u, marking new vertices 00091 // seen with the value of cm, so we can recognize a loop 00092 v = u; 00093 while (mark[v] == 0) { 00094 mark[v] = cm; 00095 e = pEdge[v]; 00096 if (e == 0) break; 00097 v = wfg->mate(v,e); 00098 } 00099 if (mark[v] == cm && e != 0) return v; 00100 00101 // find next unmarked vertex 00102 while (u <= wfg->n() && mark[u] != 0) u++; 00103 cm++; 00104 } 00105 return 0; 00106 }