private static void BuildGraph() { // For each cube from the cuboid we assign two nodes in the graph int graphNodesCount = 2 * (width * height * depth) + 2; graph = new Graph(graphNodesCount); // Add edges from the startNode to the top side of the cuboid startNode = graphNodesCount - 2; for (int w = 0; w < width; w++) { for (int h = 0; h < height; h++) { int topSideNode = CalcNodeNumber(w, h, 0, 0); int capacity = cuboid[w, h, 0]; graph.AddEdge(startNode, topSideNode, capacity); } } // Add edges between each cube and its 5 neighbors for (int d = 0; d < depth; d++) { for (int w = 0; w < width; w++) { for (int h = 0; h < height; h++) { AddEdgeIfPossible(w, h, d, w + 1, h, d); AddEdgeIfPossible(w, h, d, w - 1, h, d); AddEdgeIfPossible(w, h, d, w, h + 1, d); AddEdgeIfPossible(w, h, d, w, h - 1, d); AddEdgeIfPossible(w, h, d, w, h, d + 1); AddEdgeBetweenDoubledNode(w, h, d); } } } // Add edges from the bottom side of the cuboid the the endNode endNode = graphNodesCount - 1; for (int w = 0; w < width; w++) { for (int h = 0; h < height; h++) { int bottomSideNode = CalcNodeNumber(w, h, depth - 1, 1); int capacity = cuboid[w, h, depth - 1]; graph.AddEdge(bottomSideNode, endNode, capacity); } } }
private static int GetPathCapacity(Graph g, List<int> path) { int pathCapacity = int.MaxValue; for (int i = 0; i < path.Count - 1; i++) { int fromNode = path[i]; int toNode = path[i + 1]; int edgeCapacity = g.Capacities[fromNode, toNode]; if (edgeCapacity < pathCapacity) { pathCapacity = edgeCapacity; } } return pathCapacity; }
private static void AugmentPath(Graph g, List<int> path, int minCapacity) { for (int i = 0; i < path.Count - 1; i++) { int fromNode = path[i]; int toNode = path[i + 1]; g.Capacities[fromNode, toNode] -= minCapacity; g.Capacities[toNode, fromNode] += minCapacity; } }
private static List<int> FindAugumentingPathBFS(Graph g, int startNode, int endNode) { int?[] prevNode = new int?[g.NodesCount]; Queue<int> queue = new Queue<int>(); bool[] visited = new bool[g.NodesCount]; visited[startNode] = true; queue.Enqueue(startNode); while (queue.Count > 0) { int currentNode = queue.Dequeue(); if (currentNode == endNode) { // Build the path by using prevNode[] List<int> path = new List<int>(); int? node = endNode; while (node != null) { path.Add(node.Value); node = prevNode[node.Value]; } path.Reverse(); return path; } // Append all possible child nodes to the queue foreach (var childNode in g.ChildNodes[currentNode]) { var capacity = g.Capacities[currentNode, childNode]; if (capacity > 0 && !visited[childNode]) { prevNode[childNode] = currentNode; visited[childNode] = true; queue.Enqueue(childNode); } } } return null; }
public static int MaxFlow(Graph g, int sourceNode, int terminalNode) { int maxFlow = 0; while (true) { List<int> augumentingPath = FindAugumentingPathBFS(g, sourceNode, terminalNode); if (augumentingPath == null) { // No more augumenting paths --> max flow is found break; } int pathCapacity = GetPathCapacity(g, augumentingPath); AugmentPath(g, augumentingPath, pathCapacity); maxFlow += pathCapacity; } return maxFlow; }