/// <summary> /// Tries to Push the overflow in current vertex to neighbours if possible. /// Push is possible if neighbour edge is not full /// and any of neighbour has height of current vertex /// otherwise returns false. /// </summary> private bool push(WeightedDiGraphVertex <T, W> overflowVertex, Dictionary <T, ResidualGraphVertexStatus> vertexStatusMap) { var overflow = vertexStatusMap[overflowVertex.Key].Overflow; foreach (var edge in overflowVertex.OutEdges) { //if out edge has +ive weight and neighbour height is less then flow is possible if (edge.Value.CompareTo(@operator.defaultWeight) > 0 && vertexStatusMap[edge.Key.Key].Height < vertexStatusMap[overflowVertex.Key].Height) { var possibleWeightToPush = edge.Value.CompareTo(overflow) < 0 ? edge.Value : overflow; //decrement overflow vertexStatusMap[overflowVertex.Key].Overflow = @operator.SubstractWeights(vertexStatusMap[overflowVertex.Key].Overflow, possibleWeightToPush); //increment flow of target vertex vertexStatusMap[edge.Key.Key].Overflow = @operator.AddWeights(vertexStatusMap[edge.Key.Key].Overflow, possibleWeightToPush); //decrement edge weight overflowVertex.OutEdges[edge.Key] = @operator.SubstractWeights(edge.Value, possibleWeightToPush); //increment reverse edge weight edge.Key.OutEdges[overflowVertex] = @operator.AddWeights(edge.Key.OutEdges[overflowVertex], possibleWeightToPush); return(true); } } return(false); }
private static int getMinWeight(WeightedDiGraphVertex <int, int> currentVertex, WeightedDiGraphVertex <int, int> tgtVertex, int remainingVertexCount, HashSet <WeightedDiGraphVertex <int, int> > visited, Dictionary <string, int> cache) { var cacheKey = $"{currentVertex.Value}-{remainingVertexCount}"; if (cache.ContainsKey(cacheKey)) { return(cache[cacheKey]); } visited.Add(currentVertex); var results = new List <int>(); foreach (var vertex in currentVertex.OutEdges) { //base case if (vertex.Key == tgtVertex && remainingVertexCount == 1) { results.Add(vertex.Value); break; } if (!visited.Contains(vertex.Key)) { var result = getMinWeight(vertex.Key, tgtVertex, remainingVertexCount - 1, visited, cache); if (result != int.MaxValue) { results.Add(result + vertex.Value); } } } visited.Remove(currentVertex); if (results.Count == 0) { return(int.MaxValue); } var min = results.Min(); cache.Add(cacheKey, min); return(min); }
/// <summary> /// Increases the height of a vertex by one greater than min height of neighbours. /// </summary> private void relabel(WeightedDiGraphVertex <T, W> vertex, Dictionary <T, ResidualGraphVertexStatus> vertexStatusMap) { var min = int.MaxValue; foreach (var edge in vertex.OutEdges) { //+ive out capacity if (min.CompareTo(vertexStatusMap[edge.Key.Key].Height) > 0 && edge.Value.CompareTo(@operator.defaultWeight) > 0) { min = vertexStatusMap[edge.Key.Key].Height; } } vertexStatusMap[vertex.Key].Height = min + 1; }
/// <summary> /// Recursive DFS /// </summary> /// <param name="currentResidualGraphVertex"></param> /// <param name="visited"></param> /// <param name="searchVetex"></param> /// <returns></returns> private void DFS(WeightedDiGraph <T, W> graph, WeightedDiGraphVertex <T, W> currentResidualGraphVertex, HashSet <T> visited) { visited.Add(currentResidualGraphVertex.Value); foreach (var edge in currentResidualGraphVertex.OutEdges) { if (!visited.Contains(edge.Key.Value)) { //reachable only if +ive weight (unsaturated edge) if (edge.Value.CompareTo(operators.defaultWeight) != 0) { DFS(graph, edge.Key, visited); } } } }
/// <summary> /// Recursive DFS. /// </summary> private void dfs(WeightedDiGraphVertex <T, W> currentResidualGraphVertex, HashSet <T> visited) { visited.Add(currentResidualGraphVertex.Key); foreach (var edge in currentResidualGraphVertex.OutEdges) { if (visited.Contains(edge.Key.Key)) { continue; } //reachable only if +ive weight (unsaturated edge) if (edge.Value.CompareTo(@operator.defaultWeight) != 0) { dfs(edge.Key, visited); } } }
/// <summary> /// depth first search to find a path to sink in residual graph from source /// </summary> /// <param name="residualGraph"></param> /// <param name="source"></param> /// <param name="sink"></param> /// <returns></returns> private List <T> DFS(WeightedDiGraph <T, W> residualGraph, T source, T sink) { //init parent lookup table to trace path var parentLookUp = new Dictionary <WeightedDiGraphVertex <T, W>, WeightedDiGraphVertex <T, W> >(); foreach (var vertex in residualGraph.Vertices) { parentLookUp.Add(vertex.Value, null); } //regular DFS stuff var stack = new Stack <WeightedDiGraphVertex <T, W> >(); var visited = new HashSet <WeightedDiGraphVertex <T, W> >(); stack.Push(residualGraph.Vertices[source]); visited.Add(residualGraph.Vertices[source]); WeightedDiGraphVertex <T, W> currentVertex = null; while (stack.Count > 0) { currentVertex = stack.Pop(); //reached sink? then break otherwise dig in if (currentVertex.Value.Equals(sink)) { break; } else { foreach (var edge in currentVertex.OutEdges) { //visit only if edge have available flow if (!visited.Contains(edge.Key) && edge.Value.CompareTo(operators.defaultWeight) > 0) { //keep track of this to trace out path once sink is found parentLookUp[edge.Key] = currentVertex; stack.Push(edge.Key); visited.Add(edge.Key); } } } } //could'nt find a path if (currentVertex == null || !currentVertex.Value.Equals(sink)) { return(null); } //traverse back from sink to find path to source var path = new Stack <T>(); path.Push(sink); while (currentVertex != null && !currentVertex.Value.Equals(source)) { path.Push(parentLookUp[currentVertex].Value); currentVertex = parentLookUp[currentVertex]; } //now reverse the stack to get the path from source to sink var result = new List <T>(); while (path.Count > 0) { result.Add(path.Pop()); } return(result); }