Grafalgo
Library of useful data structures and algorithms
|
00001 // usage: sptUpdate n m maxLen repCount seed 00002 // 00003 // sptUpdate generates a random graph on n vertices with m edges. 00004 // It then computes a shortest path tree of the graph then repeatedly 00005 // modifies the shortest path tree by randomly changing the weight 00006 // of one of the edges. The edge lengths are distributed in [1,maxLen]. 00007 // 00008 // This program is not bullet-proof. Caveat emptor. 00009 00010 #include "stdinc.h" 00011 #include "List.h" 00012 #include "Dheap.h" 00013 #include "Wdigraph.h" 00014 00015 using namespace grafalgo; 00016 00017 void dijkstra(Wdigraph&, vertex, vertex*, int*); 00018 int sptUpdate(Wdigraph&, vertex*, int*, edge, int); 00019 void check(Wdigraph&, Wdigraph&); 00020 00021 int main(int argc, char* argv[]) { 00022 int i, n, m, maxLen, repCount, retVal, seed; 00023 int notZero, minTsiz, maxTsiz, avgTsiz; 00024 edge e; Wdigraph dig; 00025 00026 if (argc != 6 || 00027 sscanf(argv[1],"%d",&n) != 1 || 00028 sscanf(argv[2],"%d",&m) != 1 || 00029 sscanf(argv[3],"%d",&maxLen) != 1 || 00030 sscanf(argv[4],"%d",&repCount) != 1 || 00031 sscanf(argv[5],"%d",&seed) != 1) 00032 Util::fatal("usage: sptUpdate n m maxLen repCount seed"); 00033 00034 srandom(seed); 00035 dig.rgraph(n,m); dig.randLength(0,maxLen); 00036 00037 vertex *p = new int[n+1]; int *d = new int[n+1]; 00038 dijkstra(dig,1,p,d); 00039 00040 notZero = 0; minTsiz = dig.n(); maxTsiz = 0; avgTsiz = 0; 00041 for (i = 1; i <= repCount; i++) { 00042 e = Util::randint(1,dig.m()); 00043 retVal = sptUpdate(dig,p,d,e,Util::randint(1,maxLen)); 00044 if (retVal > 0) { 00045 notZero++; 00046 minTsiz = min(retVal,minTsiz); 00047 avgTsiz += retVal; 00048 maxTsiz = max(retVal,maxTsiz); 00049 } 00050 } 00051 00052 cout << setw(6) << notZero << " " << setw(2) << minTsiz 00053 << " " << (notZero > 0 ? double(avgTsiz)/notZero : 0.0) 00054 << " " << setw(4) << maxTsiz; 00055 } 00056 00057 int sptUpdate(Wdigraph& dig, vertex p[], int d[], edge e, int nuLen) { 00058 // Given a graph dig and an SPT sptree, update the SPT and distance vector to 00059 // reflect the change in the weight of edge e to nuLen. 00060 // Return 0 if no change is needed. Otherwise, return the number 00061 // of vertices in the subtree affected by the update. 00062 vertex u, v, x, y; edge f; 00063 int oldLen, tSiz; 00064 static int n=0; static Dheap *nheap; static List *stList; 00065 00066 // Allocate new heap and List if necessary. 00067 // For repeated calls on same graph, this is only done once. 00068 if (dig.n() > n) { 00069 if (n > 0) { delete nheap; delete stList; } 00070 n = dig.n(); 00071 nheap = new Dheap(dig.n(),2); 00072 stList = new List(dig.n()); 00073 } 00074 00075 u = dig.tail(e); v = dig.head(e); 00076 oldLen = dig.length(e); dig.setLength(e,nuLen); 00077 00078 // case 1 - non-tree edge gets more expensive 00079 if (p[v] != u && nuLen >= oldLen) return 0; 00080 00081 // case 2 - non-tree edge gets less expensive, but not enough 00082 // to change anything 00083 if (p[v] != u && d[u] + nuLen >= d[v]) return 0; 00084 00085 // In the above two cases, nv=0 and the running time is O(1) 00086 // as required. 00087 00088 // case 3 - edge gets less expensive and things change 00089 if (nuLen < oldLen) { 00090 // start Dijkstra's algorithm from v 00091 p[v] = u; d[v] = d[u] + nuLen; 00092 nheap->insert(v,d[v]); 00093 tSiz = 0; 00094 while (!nheap->empty()) { 00095 x = nheap->deletemin(); 00096 for (f = dig.firstOut(x); f !=0; f = dig.nextOut(x,f)) { 00097 y = dig.head(f); 00098 if (d[y] > d[x] + dig.length(f)) { 00099 d[y] = d[x] + dig.length(f); p[y] = x; 00100 if (nheap->member(y)) 00101 nheap->changekey(y,d[y]); 00102 else 00103 nheap->insert(y,d[y]); 00104 } 00105 } 00106 tSiz++; 00107 } 00108 return tSiz; 00109 } 00110 // In case 3, the vertices affected by the update are those that 00111 // get inserted into the heap. Hence, the number of executions of 00112 // the outer loop is O(nv). The inner loop iterates over edges 00113 // incident to the vertices for which the distance changes, hence 00114 // the number of calls to changekey is O(mv). The d-heap parameter 00115 // is 2, which gives us an overall running time of O((mv log nv). 00116 00117 // case 4 - tree edge gets more expensive 00118 00119 // Put vertices in subtree into list. 00120 stList->clear(); stList->addLast(v); x = v; tSiz = 0; 00121 do { 00122 tSiz++; 00123 for (f = dig.firstOut(x); f != 0; f = dig.nextOut(x,f)) { 00124 y = dig.head(f); 00125 if (p[y] == x) { 00126 if (stList->member(y)) { 00127 string s1; 00128 cout << "u=" << u << " v=" << v 00129 << " x=" << x << " y=" << y 00130 << endl << stList->toString(s1); 00131 } 00132 stList->addLast(y); 00133 } 00134 } 00135 x = stList->next(x); 00136 } while (x != 0); 00137 00138 // The time for the above loop is O(nv+mv) 00139 00140 // Insert vertices in the subtree with incoming edges into heap. 00141 for (x = stList->first(); x != 0; x = stList->next(x)) { 00142 // find best incoming edge for vertex x 00143 p[x] = 0; d[x] = Util::BIGINT32; 00144 for (f = dig.firstIn(x); f != 0; f = dig.nextIn(x,f)) { 00145 y = dig.tail(f); 00146 if (!stList->member(y) && d[y] + dig.length(f) < d[x]) { 00147 p[x] = y; d[x] = d[y] + dig.length(f); 00148 } 00149 } 00150 if (p[x] != 0) nheap->insert(x,d[x]); 00151 } 00152 00153 // The time for the above loop is O(mv + nvlog nv) 00154 00155 // Run Dijkstra's algorithm on the vertices in the subtree. 00156 while (!nheap->empty()) { 00157 x = nheap->deletemin(); 00158 for (f = dig.firstOut(x); f != 0; f = dig.nextOut(x,f)) { 00159 y = dig.head(f); 00160 if (d[y] > d[x] + dig.length(f)) { 00161 d[y] = d[x] + dig.length(f); p[y] = x; 00162 if (nheap->member(y)) nheap->changekey(y,d[y]); 00163 else nheap->insert(y,d[y]); 00164 } 00165 } 00166 } 00167 // Same as earlier case. The outer loop is executed nv times, 00168 // the inner loop mv times. So the overall running time is 00169 // O(mv log nv). 00170 return tSiz; 00171 } 00172 00173 void check(int s, Wdigraph& dig, Wdigraph& sptree) { 00174 // Verify that sptree is a shortest path tree of dig. 00175 vertex u,v; edge e, f; 00176 00177 // check size of sptree matches dig 00178 if (sptree.n() != dig.n() || sptree.m() != sptree.n()-1) 00179 Util::fatal("spt_check: size error, aborting"); 00180 00181 // check that sptree is a subgraph of dig 00182 for (v = 1; v <= sptree.n(); v++) { 00183 if (v == s) continue; 00184 f = sptree.firstIn(v); 00185 if (f == 0) 00186 cout << "check: non-root vertex " << v 00187 << " has no incoming edge\n"; 00188 u = sptree.tail(f); 00189 for (e = dig.firstIn(v); ; e = dig.nextIn(v,e)) { 00190 if (e == 0) { 00191 cout << "check: edge (" << u << "," << v 00192 << ") in sptree is not in dig\n"; 00193 } 00194 if (dig.tail(e) == u) break; 00195 } 00196 } 00197 00198 // check that sptree reaches all the vertices 00199 bool* mark = new bool[sptree.n()+1]; int marked; 00200 for (u = 1; u <= sptree.n(); u++) mark[u] = false; 00201 mark[s] = true; marked = 1; 00202 List q(dig.n()); q.addLast(s); 00203 while (!q.empty()) { 00204 u = q.first(); q.removeFirst(); 00205 for (e = sptree.firstOut(u); e != 0; e = sptree.nextOut(u,e)) { 00206 v = sptree.head(e); 00207 if (!mark[v]) { 00208 q.addLast(v); mark[v] = true; marked++; 00209 } 00210 } 00211 } 00212 if (marked != sptree.n()) { 00213 cout << "check: sptree does not reach all vertices\n"; 00214 return; 00215 } 00216 00217 // check that tree is minimum 00218 int du, dv; string s1; 00219 for (u = 1; u <= dig.n(); u++) { 00220 du = sptree.firstIn(u) == 0 ? 00221 0 : sptree.length(sptree.firstIn(u)); 00222 for (e = dig.firstOut(u); e != 0; e = dig.nextOut(u,e)) { 00223 v = dig.head(e); edge vpe = sptree.firstIn(v); 00224 dv = vpe == 0 ? 0 : sptree.length(vpe); 00225 if (dv > du + dig.length(e)) 00226 cout << "check: " << dig.edge2string(e,s1) 00227 << " violates spt condition\n"; 00228 if (vpe != 0 && sptree.tail(vpe) == u && 00229 dv != du + dig.length(e)) 00230 cout << "check: tree edge " 00231 << sptree.edge2string(vpe,s1) 00232 << " violates spt condition\n"; 00233 } 00234 } 00235 }