The book said that we can select an applicable operation in O(1) time, and use O(V) and O(1) time for relabel and push operation respectively.
First note that all operations are performed on overflowing vertices other than s or t. We may store all these vertices in a data structure and when that structure becomes empty, the algorithm terminates. When nonempty, pick an arbitrary vertex u from it. If there is some admissible edge (u,v)(that is, (u,v) is in the residual network and h[u]=h[v]+1), a push operation is applicable. Otherwise, a relabel operation is applicable.
So we may wish to maintain a list of admissible edges for every vertex. Every time, either a push or relabel operation may be applicable depending on whether the corresponding list is empty or not. After a push, the only possible influence on these lists is that (u, v) has to be removed from the list corresponding to u after a saturating push. If we simply associate every edge a pointer to the nodes in these lists, the removal can be done in O(1) time. Each edge (u,v) may appear in these lists at most once, for h[u]=h[v]+1 and h[v]=h[u]+1 cannot hold at the same time.
But after a relabel operation on u, some edges (u,v) has to be inserted into the list corresponding to u, and all edges (v,u) appearing in other lists has to be removed. The insertion is simple. But we have to check the lists for every other vertex in order to remove edges ending at u, thus resulting in O(E) time complexity. The solution is to use orthogonal lists. Intuitively, all admissible edges leaving u are on the horizontal line, while those entering u are on the vertical line. Now, the insertion and removal operations take time proportional to the out degrees and in degrees of vertex u. A single operation of both types is now a little bit more complicated, but requires only O(1) time.
Finally, a simple list suffices for the data structure mentioned in the second paragraph. Every time, pick the vertex at the end of that list. Relabel doesn't change the flow of any vertex, so no updates are necessary. After a push from u to v, remove u if it is no longer overflowing and insert v if its flow is 0 previously.
Now, the generic push-relabel algorithm is implemented using a total time of O(V2E).
Showing posts with label CLRS. Show all posts
Showing posts with label CLRS. Show all posts
Thursday, November 17, 2011
The Initialization of the Generic Push-Relabel Algorithm
When we apply the generic push-relabel algorithm, we first label s as |V| and t as 0, and all edges starting from s are pushed in as many units of flow as possible, i.e they are saturated. But why these operations are necessary and reasonable is not stated explicitly.
What if we label s and t with different values? The difference between h[s] and h[t], h[s]-h[t], must be no smaller than |V|, for otherwise the statement that there is no path from s to t in the residual network never holds. And when the preflow becomes a flow, it is not necessarily a maximum flow since there may be augmenting paths. If s and t are labeled with greater values other than |V| and 0, the bounds on the number of relabel, saturating push and thus non-saturating push will become higher. Intuitively, there must be redundant relabel operations before extra flows are pushed to t or back to s since h[s] and h[t] become greater, and during that process, extra push operations between vertices other than s and t occur.
Suppose for some neighbor u of s, we initially push less flow into edge (s,u) than c(s,u). Then (s,u) is in the residual network. But h[s]=|V|>=2>h[u]+1=0+1=1, i.e. h is no longer a valid height function.
What if we label s and t with different values? The difference between h[s] and h[t], h[s]-h[t], must be no smaller than |V|, for otherwise the statement that there is no path from s to t in the residual network never holds. And when the preflow becomes a flow, it is not necessarily a maximum flow since there may be augmenting paths. If s and t are labeled with greater values other than |V| and 0, the bounds on the number of relabel, saturating push and thus non-saturating push will become higher. Intuitively, there must be redundant relabel operations before extra flows are pushed to t or back to s since h[s] and h[t] become greater, and during that process, extra push operations between vertices other than s and t occur.
Suppose for some neighbor u of s, we initially push less flow into edge (s,u) than c(s,u). Then (s,u) is in the residual network. But h[s]=|V|>=2>h[u]+1=0+1=1, i.e. h is no longer a valid height function.
Wednesday, March 16, 2011
Finding one good chip using less than n pairwise tests: solution to CLRS problem 4-6
Part (b) says that when there are more than half good chips and your goal is to find out ONE of them, you can use divide-and-conquer techniques and floor(n/2) pairwise tests can reduce the problem size to nearly half.
We notice that in a test, when "Good-Good" is reported, the two must be both good or both bad. Otherwise, they cannot be both good. So we'll choose any one from such groups and ignore all other groups.
When the number of chips is even, the situation is quite straightforward. Consider the extreme condition in which there are (n-1) bad chips and (n+1) good ones. The number of groups in which both two are good must be larger than the groups in which both two are bad. So after the "divide", the property that there are more than half good chips is preserved.
When the number of chips is odd, the problem becomes a little bit intricate. Again consider the extreme condition in which there are n bad chips and (n+1) good ones. We must take out a chip, namely X, and perform pairwise tests for the others. When X is bad, it is OK. But what if X is good? We can easily see that after the "divide", the number of good ones must be no smaller than the number of bad ones no matter what you take out. So when there are odd number of chips after the "divide", we can conclude that the property is actually preserved(Note that if there is exactly 1 left, then it must be good) and we can simply ignore X. Otherwise, we cannot tell whether X is good or bad, but from part (a) we know that when there are equal numbers of good chips and bad chips, we may not be able to distinguish any one as good if all bad chips can conspire. So just keep this unknown chip and proceed further. If the one taken out is good and all bad ones do conspire, at last we know X is in fact good. Otherwise, we will find another good one.
This post gives a more detailed explanation in Chinese.
We notice that in a test, when "Good-Good" is reported, the two must be both good or both bad. Otherwise, they cannot be both good. So we'll choose any one from such groups and ignore all other groups.
When the number of chips is even, the situation is quite straightforward. Consider the extreme condition in which there are (n-1) bad chips and (n+1) good ones. The number of groups in which both two are good must be larger than the groups in which both two are bad. So after the "divide", the property that there are more than half good chips is preserved.
When the number of chips is odd, the problem becomes a little bit intricate. Again consider the extreme condition in which there are n bad chips and (n+1) good ones. We must take out a chip, namely X, and perform pairwise tests for the others. When X is bad, it is OK. But what if X is good? We can easily see that after the "divide", the number of good ones must be no smaller than the number of bad ones no matter what you take out. So when there are odd number of chips after the "divide", we can conclude that the property is actually preserved(Note that if there is exactly 1 left, then it must be good) and we can simply ignore X. Otherwise, we cannot tell whether X is good or bad, but from part (a) we know that when there are equal numbers of good chips and bad chips, we may not be able to distinguish any one as good if all bad chips can conspire. So just keep this unknown chip and proceed further. If the one taken out is good and all bad ones do conspire, at last we know X is in fact good. Otherwise, we will find another good one.
This post gives a more detailed explanation in Chinese.
Wednesday, March 9, 2011
Finding the second smallest element: solution to CLRS exercise9.1-1
The statement says that this can be achieved using exactly n+ceiling(lg(n))-2 comparisons in the worst case. I thought for a long time but didn't get the right idea.
This post by n1b-algo gives a detailed explanation.
Its main idea is to build a comparison tree and check the elements "knocked out" by the smallest one afterwards. The smallest element is placed at the root, and it beats exactly one element at each level except the root, so there are ceiling(lg(n))-1 elements to check in total, since the binary tree with n leaves at the bottom level and without any other leaves has ceiling(lg(n)) levels excluding the root.
This post by n1b-algo gives a detailed explanation.
Its main idea is to build a comparison tree and check the elements "knocked out" by the smallest one afterwards. The smallest element is placed at the root, and it beats exactly one element at each level except the root, so there are ceiling(lg(n))-1 elements to check in total, since the binary tree with n leaves at the bottom level and without any other leaves has ceiling(lg(n)) levels excluding the root.
Subscribe to:
Posts (Atom)