// CS 1501 // Demonstration of Edmonds and Karp PFS implementation of Ford-Fulkerson method // of calculating network flow. This implementation is done using an adjacency // matrix. #include #include #include #include const int maxV = 903; // to allow for 30x30 grid of vertices in m30.max int V, E, source, sink; int size[maxV][maxV]; int flow[maxV][maxV]; int val[maxV]; int dad[maxV]; int intree[maxV]; // I added this array so we don't have to worry about negatives // indicating "not yet in the tree" as well as priorities. int DEBUG = 0; void getdata() { ifstream infile; char ifname[20]; bool ok = false; while (!ok) // prompt for name until it is legal { cout << "File name? > "; cin >> setw(20) >> ifname; infile.open(ifname, ios::in); if (infile.good()) ok = true; // either file opened successfully else cout << "File " << ifname << " does not exist!" << endl; } char dum1[10], dum2[10]; // Note: the input is done here in a PRIMITIVE way, relying not on the // code symbols (ex. p, n, a) of the file but rather on the sequence of // lines. infile.ignore(100,'\n'); // skip first line of file infile.ignore(100,'\n'); // skip second line of file infile >> dum1 >> dum2 >> V >> E; // read in #vertices and #edges infile >> dum1 >> source >> dum2; infile >> dum1 >> sink >> dum2; int j, x, y, w; for (x = 1; x <= V; x++) for (y = 1; y <= V; y++) { size[x][y] = 0; flow[x][y] = 0; } for (j = 1; j <= E; j++) // initialize capacities based on { // the edge weights read in infile >> dum1 >> x >> y >> w; size[x][y] = w; size[y][x] = -w; } infile.close(); } // Debugging code to show the matrices. void showmat() { for (int i = 1; i <= V; i++) cout << " " << setw(2) << i << " "; cout << endl; for (int i = 1; i <= (10*V); i++) cout << "-"; cout << endl; for (int i = 1; i <= V; i++) { for (int j = 1; j <= V; j++) cout << "(" << setw(3) << size[i][j] << "," << setw(3) << flow[i][j] << ") "; cout << endl; } } // Similar to the PFS MST algorithm, we are using the val array here as a // priority queue to decide which vertex will be added to the (maximum) // spanning tree next. When the vertex added to the tree is the sink, the // augmenting path is complete. If the sink is not reached, no augmenting // path exists int bestaugpath(int source, int sink) { int k, t, max = 0; // Since the val array is no longer concerned with designating the fringe, // it is now initialized to 0 for all vertices. It will store the edge // weights used to choose the next vertex in the tree for (k = 1; k <= V; k++) { val[k] = 0; dad[k] = 0; intree[k] = 0;} val[0] = 0; val[source] = MAXINT; for (k = source; k != 0; k = max, max = 0) { if (DEBUG == 1) { cout << "val = "; for (int mm = 1; mm <= V; mm++) cout << setw(5) << val[mm] << " "; cout << endl; cout << "intree = "; for (int mm = 1; mm <= V; mm++) cout << setw(5) << intree[mm] << " "; cout << endl; cout << "k (next vertex added) = " << k << endl; } intree[k] = 1; if (DEBUG == 1) cout << "Updating neighbors of " << k << endl; for (t = 1; t <= V; t++) { if (intree[t] == 0) // only update if not yet in "tree" { int prio = -flow[k][t]; // calculate priority if (size[k][t] > 0) prio += size[k][t]; if (prio > val[k]) prio = val[k]; // flow along a link // cannot be greater than the flow along the // previous link in the path if (prio > val[t]) // if greater than old { // update to new and val[t] = prio; // change dad dad[t] = k; if (DEBUG == 1) { cout << " val[" << t << "] = " << val[t] << " "; cout << "dad[" << t << "] = " << k << endl; } } if (val[t] > val[max]) // keep track of biggest { max = t; if (DEBUG == 1) cout << " New max is now " << max << endl; } } } if (max == sink) return 1; // if biggest is sink, we are done, since // that is the vertext we are trying to reach } return (0); // return 0 to indicate that sink was not reached } void main() { getdata(); if (V <= 10) DEBUG = 1; // don't show debug stuff if V > 10 //showmat(); int totalflow = 0; int numaugments = 0; for (;;) { if (!bestaugpath(source, sink)) break; int y = sink; int x = dad[sink]; totalflow += val[sink]; numaugments++; while (x != 0) // update residual graph by going { // backward along augmenting path flow[x][y] = flow[x][y] + val[sink]; // from sink to source flow[y][x] = -flow[x][y]; y = x; x = dad[y]; } if (DEBUG == 1) { cout << "Flow augmented by " << val[sink] << endl; cout << "Path (starting at sink) = "; for (int i = sink; i != 0; i = dad[i]) cout << i << ", "; cout << endl; showmat(); cout << endl << endl; } } cout << endl << "After " << numaugments << " augmentations, the " << "Max Flow result is: " << totalflow << endl; //showmat(); }