Algorithmic Complexity for Max Flow Algorithm - algorithm

I'm studying computer science/operations research, and right now I am interested in the maximum flow problem. I wrote an algorithm that solves the problem, but am having trouble figuring out the computational complexity. Python-esque pseudo-code is below:
function max_flow(graph,current_node,limit):
if limit <= 0:
return 0
else if node == graph.sink:
return limit
else:
total = 0
for each node connected to current_node:
cap = graph.capacity(current_node,node)
if cap > 0:
next_limit = min(cap, limit - total)
next_max_flow = max_flow(graph,node,next_limit)
total += next_max_flow
graph.capacity(current_node,node) -= next_max_flow
return total
Where graph.capacity(a,b) means the capacity of the arc from a to b. To find the total max flow, one would call the algorithm as max_flow(graph,graph.source,infinity).
I proved to myself that the algorithm is correct (although if that is also wrong, feel free to correct me), and my belief about the complexity is that the algorithm runs in O(|V|2), where |V| is the number of vertices. The reasoning is:
In the worst case, every node is connected to every other node, so it is a complete digraph. This means that at most, each node has |V| - 1 edges. However, due to skew symmetry, if the capacity from a to b is positive, the capacity from b to a must be negative. So, if the source has |V| - 1 positive-capacity edges, then the next-highest node could have at most |V| - 2 positive-capacity edges, since at least one edge must have negative capacity. Because of this, the total number of positive-capacity edges is at most (|V|-1)*(|V|-2) / 2 = O(|V|2).
And that's sort of where I get stuck. Intuitively, it sounds like going through each of |V| nodes a maximum of |V| times, which results in O(|V|2). However, part of me thinks that the actual complexity is O(|V|3), but I can't find any rigorous explanation for either of these. Can someone give me a push in the right direction?
Note: none of this is homework, or a part of any class.

Complexity
I think this has exponential complexity for acyclic graphs because of the recursive calls. (For cyclic graphs it will never complete so has infinite complexity.)
Example
Suppose we have a start node, 100 nodes arranged in a 10*10 grid, and a sink node.
The start connects to all 10 nodes in column 1 (with capacity 1).
Each node in column x connects to all nodes in column x+1 (with capacity 1).
But no node connects to the sink node.
Then your algorithm will have to try all 10^10 ( = 10,000,000,000) possible routes through the matrix to discover that the maximum flow is equal to 0.

Related

Number of walks from source to sink with exactly h hops

Given an un-directed graph, a starting vertex and ending vertex. Find the number of walks (so a vertex can be visited more than once) from the source to the sink that involve exactly h hops. For example, if the graph is a triangle, the number of such paths with h hops is given by the h-th Jakobstahl number. This can be extended to a fully connected k-node graph, producing the recurrence (and closed form solution) here.
When the graph is an n-sided polygon, the accepted answer here expresses the number of walks as a sum of binomial terms.
I assume there might be an efficient algorithm for finding this number for any given graph? We can assume the graph is provided in adjacency matrix or adjacency list or any other convenient notation.
A solution to this would be to use a modified BFS with two alternating queues and a per-node counter for paths to this node of a certain length:
paths(start, end, n):
q = set(start)
q_next = set()
path_ct = map()
path_ct_next = map()
path_ct[start] = 1
for i in [0, n): # counting loop
for node in q: # queue loop
for a in adjacent(node): # neighbor-loop
path_ct_next[a] += path_ct[node]
q_next.add(a)
q = q_next
q_next = set()
path_ct = path_ct_next
path_ct_next = map()
return path_ct_next[end]
The basic assumption here is that map() produces a dictionary that returns zero, if the entry doesn't yet exist. Otherwise it returns the previously set value. The counting-loop simply takes care of doing exactly as many iterations as hops as required. The queue loop iterates over all nodes that can be reached using exactly i hops. In the neighbor-loop finally all nodes that can be reached in i + 1 hops are found. In this loop the adjacent nodes will be stored into a queue for the next iteration of counting-loop. The number of possible paths to reach such a node is the sum of the number of paths to reach it's predecessors. Once this is done for each node of the current iteration of counting-loop, the queues and tables are swapped/replaced by empty instances and the algorithm can start over.
If you take the adjacency matrix of a graph and raise it to the nth power, the resulting matrix counts the number of paths from each node to each other that uses exactly n edges. That would provide one way of computing the number you want - plus many others you aren’t all that interested in. :-)
Assuming the number of paths is “small” (say, something that fits into a 64-bit integer), you could use exponentiation by squaring to compute the matrix in O(log n) multiplies for a total cost of O(|V|ω log n), where ω is the exponent of the fastest matrix multiplication algorithm. However, if the quantity you’re looking for doesn’t fit into a machine word, then the cost of this approach will depend on how big the answer is as the multiplies will take variable amounts of time. For most graphs and small n this won’t be an issue, but if n is large and there are other parts of the graph that are densely connected this will slow down a bit.
Hope this helps!
You can make an algorithm that keep searching all possible paths , but with a variable that will contain your number of hops
For each possible path , each hop will decrement that variable and when arriving to zero your algorithm goes to trying another path , and if ever a path arrives to the target before making variable reachs zero , this path will be added to the list of your desired paths

Pathfinding task - how can I find next vertex on the shortest path from A to B faster that O ( n )?

I have a quite tricky task to solve:
You are given a N * M board (1 <= N, M <= 256). You can move from each field to it's neighbouring field (moving diagonally is not allowed). At the beginning, there are two types of fields: active and blocked. You can pass through active field, but you can't go on the blocked one. You have Q queries (1 <= Q <= 200). There are two types of queries:
1) find the next field (neighbouring to A) that lies on the shortest path from field A to B
2) change field A from active to blocked or conversly.
The first type query can be easily solved with simple BFS in O(N * M) time. We can represent active and blocked fields as 0 or 1, so the second query could be done in constant time.
The total time of that algorithm would be O(Q (number of queries) * N * M).
So what's the problem? I have a 1/60 second to solve all the queries. If we consider 1 second as 10^8 calculations, we are left with about 1,5 * 10^6 calculations. One BFS may take up to N * M * 4 time, which is about 2,5 * 10^5. So if Q is 200, the needed calculations may be up to 5 * 10^7, which is way too slow.
As far as I know, there is no better pathfinding algorithms than BFS in this case (well, I could go for an A*, but I'm not sure if it's much quicker than BFS, it's still worst-case O(|E|) - according to Wikipedia ). So there's not much to optimize in this area. However, I could change my graph in some way to reduce the amount of edges that the algorithm would have to process (I don't need to know the full shortest path, only the next move I should make, so the rest of the shortest path can be very simplified). I was thinking about some preprocessing - grouping vertices in a groups and making a graph of graphs, but I'm not sure how to handle the blocked fields in that way.
How can I optimize it better? Or is it even possible?
EDIT: The actual problem: I have some units on the board. I want to start moving them to the selected destination. Units can't share the same field, so one can block others' paths or open a new, better paths for them. There can be a lot of units, that's why I need a better optimization.
If I understand the problem correctly, you want to find the shortest path on a grid from A to B, with the added ability that your path-finder can remove walls for an additional movement cost?
You can treat this as a directed graph problem, where you can move into any wall-node for a cost of 2, and into any normal node for a cost of 1. Then just use any directed-graph pathfinding algorithm such as Dijkstra's or A* (the usual heuristic, manhatten distance, will still work)

Recurrence: T(n/4) + T(n/2) + n^2 with tree methods

I'm trying to solve this exercise with tree method but I've a doubt about two parts:
1) In the T(?) column, is it correct using (n^2/2^i) instead of (n/2^i)? I'm asking because this is the part which cause me the error;
2) Is the last multiplication correct (it's between the number of nodes and the time)? After finding the i value I have to create a serie which starts from 0 to the result of the multiplication, right? And as variable of the serie have I to use 2^i (the number of nodes)?
The column for the number of nodes is misleading.
Each node has a cost of (m/k)^2 where k is whatever the denominator of the node is. With the structure you have using, the nodes in each level will have a variety of denominators. For example, your level 2 should contain the nodes [(m/16), (m/8)], [(m/8), (m/4)].
The cost for a level is the sum of the cost of each node in that level. Since each node has a different cost, you cannot multiply the number of nodes by a value to find the cost of a level, you have to add them up individually.
The total cost is the sum of the cost of each level. The result of this calculation may result in a logarithm, or it may not. It depends on the cost of each level and the number of levels.
Hint: Pascal's Triangle

A Dynamic Programming or Graph Algorithm, a Nice Questions

An agent is works between n producer and m consumers. ith producer, generates s_i candy and jth consumer consumes b_j candy in this year. For each candy that sales, agent get 1 dollar payoff. For some problems, one strict rule was defined that a producer should be sales candy to any producer that the distance between them is not greater than 100 KM (kilometers). if we have list of all pairs of producer-consumer that the distance between them is lower than 100 KM, which of the following algorithm is goof for finding maximum payoffs? (suppose s_i and b_j may be becomes very large).
1) Maximal Matching
2) Dynamic Programming
3) Maximum Flow
4) 1 , 3
this is a last question on 2013-Final Exam on DS course. Any hint or idea?
To my understanding, the problem can be solved as a Maximum Bipartite Matching, however the modelling requires the graph to be relatively large compared to the original input; for every feasible edge (s_i,b_j) introduce s_i nodes for the producer partition and b_j for the consumer partition and connect each producer node of the to each consumer node of them.
The problem can be modelled as Maximum Flow Problem on a bipartite graph, however; the flow on each feasible edge (s_i,b_j) is constrained by 0 from below and min{s_i,b_j} from above, as the flow must be nonnegative, but may exceed neither the producer's nor the consumer's capacity.
Concerning a solution via Dynamic Prgramming, consider the following sketch of a recurrence relation for Maximum Bipartite Matching. Let n and m denote the number of nodes in the first and second partition, respectively. Fix a node a in the first partition; either a is not matched or matched to one of its neighbors; in either case, each possibility is evaluated, recursively evaluating an instance where the partitions have n-1 and m or n-1 and m-1 nodes, respectively; the best of these choices is taken.
To put it all in a nutshell, apparently all of the proposed approaches yield valid solutions; however, the modelling as network flow seems to be most natural.

How to solve this with simple forward-backward algorithm?

I've been playing around with the forward-backward algorithm to find the most efficient (determined by a cost function dependent on how a current state differs from the next state) path to go from State 1 to State N. In the picture below, a short version of the problem can be seen with just 3 States and 2 Nodes per State. I do forward-backward algorithm on that and find the best path like normal. The red bits in the pictures are the paths checked during forward propagation bit in the code.
Now the interesting bit, I now want to find the best 3-State Length path (as before) but now only Nodes in the first State are known. The other 4 are now free-floating and can be considered to be in any State (State 2 or State 3). I want to know if you guys have a good idea of how to do this.
Picture: http://i.imgur.com/JrQ2tul.jpg
Note: Bear in mind the original problem consists of around 25 States and 100 Nodes per State. So, you'll know the State of around 100 Nodes in State 1 but the other 24*100 Nodes are Stateless. In this case, I want find a 25-State length path (with minimum cost).
Addendum: Someone pointed out a better algorithm would be Viterbi's algorithm. So here is a problem with more variables thrown in. Can you guys explain how would that be implemented? Same rules apply, the path should start from one of the Nodes in State 1 (Node a or Node b). Also, the cost function using the norm doesn't make sense in this case since we only have one property (Size of node) but in the actual problem I'm expecting a lot more properties.
A variation of Dijkstra's algorithm might be faster for your problem than the forward-backward algorithm, because it does not analyze all nodes at once. Dijkstra is a DP algorithm after all.
Let a node be specified by
Node:
Predecessor : Node
Total cost : Number
Visited nodes : Set of nodes (e.g. a hash set or other performant set)
Initialize the algorithm with
open set : ordered (by total cost) set of nodes = set of possible start nodes (set visitedNodes to the one-element set with the current node)
( = {a, b} in your example)
Then execute the algorithm:
do
n := pop element from open set
if(n.visitedNodes.count == stepTarget)
we're done, backtrace the path from this node
else
for each n2 in available nodes
if not n2 in n.visitedNodes
push copy of n2 to open set (the same node might appear multiple times in the set):
.cost := n.totalCost + norm(n2 - n)
.visitedNodes := n.visitedNodes u { n2 } //u = set union
.predecessor := n
next
loop
If calculating the norm is expensive, you might want to calculate it on demand and store it in a map.

Resources