Vous êtes sur la page 1sur 9

Algorithms for optimization and statistical inference - 01NWJPF Mid Term Exam - A.Y.

2011/2012 Marco Jacopo Ferrarotti - 185480

Short paths, big improvements (Edmonds Karp Algorithm)


Abstract
In the Ford-Fulkerson algorithm, we are free to Increase the flow along any augmenting path. Suppose we always use one of the shortest paths from s to t in Gf, where shortest means simply the number of edges, regardless of their capacity. Furthermore we increase the flow as much as possible, i.e. by the minimum of cf(e) over all the edges e appearing in . Show that this improved algorithm finds the maximum flow in at most |V||E|=O(n3) iterations even if the capacities are exponentially large, and so that Max Flow is in P.

Definitions
Lets define all the elements that we are going to use further in the demonstration: , , directed graph under analysis (flow network), we consider such a graph valid if: there is only one source node ; there is only one sink node ; for each node exist always a path ; , , capacity (positive quantities associated with each edge of the graph) , , flow for which the following three properties are satisfied: , , , (, ) 0; , , , = (, ); , , , = 0; , = , (, ), residual capacity = , : , > , set of residual edges (, ), residual graph , augmenting path (path from to within ) of length = , : (, ) , residual capacity of the augmenting path (, ), minimum distance between nodes , in

Ford-Fulkerson Algorithm
The starting point of the algorithm proposed in the Abstract is the Ford-Fulkerson algorithm, we now briefly introduce it giving also a first upper bound for its execution time. The Ford-Fulkerson algorithm is an iterative scheme that, starting from an initial flow of 0, increase it at least by one unit at each step until the maximum is reached. We have mainly two operations performed during each cycle : find an augmenting path in the residual graph; update the flow along pd by the quantity ( ); For the sake of completeness we report here a possible pseudo-code for the algorithm: 1. initialize f matrix to 0; 2. while it exist an augmenting path pd in Gr 3. compute cr (pd ); 4. for each (u, v) in pd 5. update f u, v = f u, v + cr (pd ); 6. update f v, u = f u, v ; 7. return f; Looking to the algorithm it is obvious that the running time will strongly depend on how we choose the augmenting path at each step. Let us compute a first rough upper bound for the execution time, if the maximum flow found by the algorithm is , then the algorithm runs in time (): The main loop of the algorithm runs at most time (at each step the flow increase at least by one unit); If we find the augmenting path with a depth-first search at each step we spent + = () operations.

Shortest Path Improvement


We want now to demonstrate that if at each step of the Ford-Fulkerson algorithm we choose the shortest augmenting path among all the possibilities, then we can improve the upper bound for the number of iterations of the main loop to (). We divide the demonstration in two part: 1. The shortest path distance from the source node to another node , increase monotonically during the algorithm:

Let us suppose the converse to be true, , | < , | and let us suppose to pick the that have the minimum , | ; If is the node that precede in the shortest path we know that: , | = , | and from the second of the assumptions that we have made: , | , |

Now that , | , if this is true we have: , | , | + , | + = , | which is in contradiction to the hypothesis that , | < , |

So , | and , | which means that we have increased the flow from to so the shortest path from to must had (, ) as last edge: , | = , | , | = , | This is in contradiction with our assumption and the first part of the proof is demonstrated.

2. The number of iterations of the main loop of the algorithm is (): An edge (, ) is critical on an augmenting path if = (, ), from this it is obvious that after a step of the algorithm along all the critical edges of that augmenting path will be removed from Let us take an edge (, ) that become critical for the first time, because of the nature of the choice of (shortest augmenting path) we have: , | = , | + Once that we have augmented the flow along the edge (, ) will be removed from and it will reappear later on only when (, ) belong to a shortest augmenting path. When (, ) belong to a shortest augmenting path we have: , | = , | + But thanks to the result that we have proved before, we have:

, | = , | + , | + = , | + So before the edge (, ) can become again critical, the distance , has increased its value at least by two units. The distance of one node from the source can become at most , = so each edge can become critical at most

times.

In conclusion during the algorithm the total number of critical edges that we can have goes like () and for each iteration we choose at least one of such critical edges so we have obtained the desired result.

Conclusions
To conclude we can summarize the results obtained for the proposed algorithm as follow: If we improve the Ford-Fulkerson algorithm in such a way that at each iteration the augmenting path is the shortest possible, then the algorithm converge in () iterations; If in such an algorithm we implement the search of the shortest augmenting path with a breadth-first search (which runs in () ) then the entire algorithm computing time is bounded from = ; From the last consideration we can therefore say that (the maximum flow problem belong to the Polynomial Computational Complexity Class)

Appendix - Implementation of the algorithm in C


As appendix I attach the source code of my personal implementation of the proposed algorithm written in C language.

EdmondsKarp.c

17/07/12 01:56

/************************************************************************* ** EdmondsKarp.c ** ** Algorithms for optimization and statistical inference - 01NWJPF ** Mid Term Exam - A.Y. 2011/2012 ** Marco Jacopo Ferrarotti - 185480 ** ** Implementation of the Edmonds-Karp algorithm *************************************************************************/ #include <stdio.h> #include <stdlib.h> typedef struct lstElement { //data that the element hold int node; //next element in the list struct lstElement* nxt; }LSTELEMENT; void lstPush(LSTELEMENT** lst, int node); LSTELEMENT* lstPop(LSTELEMENT** lst); int* vctIntAllocate(int size); LSTELEMENT** vctLstAllocate(int size); int** mtrIntAllocate(int r, int c); void initialize(int** F, int** C, LSTELEMENT** A, int n, int maxC); int** generateC(int n, int cMax); int* augPath(int** C, LSTELEMENT** A, int** F, int n, int maxC, int s, int t); int main(int argc, char** argv) { //number of vertices int n; //max capacity int maxC; //capacity matrix int** C; //adiacency lists LSTELEMENT** A; //index of the source int s; //index of the sink int t; //current max flow int fMax; //flow matrix int** F; //augmenting path int* P; int v; int u;

Page 1 of 5

EdmondsKarp.c

17/07/12 01:56

n = atoi(argv[1]); maxC = atoi(argv[2]); C = mtrIntAllocate(n,n); A = vctLstAllocate(n); s = 0; t = n-1; fMax = 0; F = mtrIntAllocate(n,n); initialize(F,C,A,n,maxC); //while there is an augmenting path while((P=augPath(C,A,F,n,maxC,s,t))[n]!=0){ //sum the residual capacity of P to fMax fMax += P[n]; //augment the flow along the augmenting path P v = t; while(v!=s){ u = P[v]; F[u][v] += P[n]; F[v][u] = -F[u][v]; v = u; } } //Print out the flow matrix and the max flow found for(u=0;u<n;u++){ for(v=0;v<n;v++){ printf("%d\t",F[u][v]); } printf("\n"); } printf("%d",fMax); } void initialize(int** F, int** C, LSTELEMENT** A, int n, int maxC) { int i; int j; LSTELEMENT* newElm; //initialize flow matrix to 0 for(i=0;i<n;i++) { for(j=0;j<n;j++){ F[i][j] = 0; } } //generate a valid capacity matrix C = generateC(n, cMax); //built adiacency lists starting from capacity matrix

Page 2 of 5

EdmondsKarp.c

17/07/12 01:56

for(i=0;i<n;i++){ A[i] = NULL; for(j=0;j<n;j++){ if(C[i][j]!=0){ lstPush(&(A[i]),j); } } } } int** generateC(int n, int cMax){ int** C; C = mtrIntAllocate(n,n); C[0][0] C[0][1] C[0][2] C[0][3] C[1][0] C[1][1] C[1][2] C[1][3] C[2][0] C[2][1] C[2][2] C[2][3] C[3][0] C[3][1] C[3][2] C[3][3] } int* augPath(int** C, LSTELEMENT** A, int** F, int n, int maxC, int s, int t){ int* path; int i; LSTELEMENT* q; LSTELEMENT* qp; int u; int v; //initialize the path vector path = vctIntAllocate(n+1); for(i=0;i<n;i++){ if(i==s){ //s has no parent node for sure path[i] = -2; } else{ path[i] = -1; } } //hold the residual capacity of the path = = = = = = = = = = = = = = = = 0; 5; 1; 0; 0; 0; 3; 2; 0; 0; 0; 4; 0; 0; 0; 0;

Page 3 of 5

EdmondsKarp.c

17/07/12 01:56

path[n] = maxC; //queue to perform the BFS algorithm q = (LSTELEMENT*)malloc(sizeof(LSTELEMENT)); lstPush(&q,s); //while there is a node in queue while(q!=NULL){ //pop an element from the queue u = (*lstPop(&q)).node; qp = A[u]; //while there is an element in the adiacency list of u while(qp!=NULL){ v = (*qp).node; //if the node was never visited and has a residual capacity if(C[u][v]-F[u][v]>0 && path[v]==-1){ //trace the step u->v path[v] = u; //if the residual capacity is the minimum one save it if(C[u][v]-F[u][v]<path[n]){ path[n] = C[u][v]-F[u][v]; } //if we haven't reached the sink contiunue the search if(v!=t){ lstPush(&q,v); } //otherwise return the path found else{ return path; } } qp = (*qp).nxt; } } path[n] = 0; return path; } void lstPush(LSTELEMENT** lst, int node) { LSTELEMENT* newElm; newElm = (LSTELEMENT*)malloc(sizeof(LSTELEMENT)); (*newElm).node = node; (*newElm).nxt = *lst; *lst = newElm; return; } LSTELEMENT* lstPop(LSTELEMENT** lst) { LSTELEMENT* elm; LSTELEMENT* pElm; pElm = NULL; elm = *lst;

Page 4 of 5

EdmondsKarp.c

17/07/12 01:56

while((*elm).nxt!=NULL){ pElm = elm; elm = (*elm).nxt; } if(pElm != NULL){ (*pElm).nxt = NULL; } else { *lst = NULL; } return elm; } LSTELEMENT** vctLstAllocate(int size){ return (LSTELEMENT**)malloc(sizeof(LSTELEMENT*)*size); } int* vctIntAllocate(int size){ return (int*)malloc(sizeof(int)*size); } int** mtrIntAllocate(int r, int c){ int** mtr; int i; mtr = (int**)malloc(sizeof(int*)*r); for(i=0;i<r;i++){ mtr[i] = (int*)malloc(sizeof(int)*c); } return mtr; }

Page 5 of 5

Vous aimerez peut-être aussi