// Find a shortest path between the two nodes // by using a label correcting algorithm. // Return the path's total cost. public int FindLabelCorrectingPath(NetworkNode fromNode, NetworkNode toNode, out List <NetworkNode> pathNodes, out List <NetworkLink> pathLinks) { // Build a shortest path tree. FindLabelCorrectingPathTree(fromNode); // Follow the tree's links back from toNode to fromNode. return(FindSpanningTreePath(fromNode, toNode, out pathNodes, out pathLinks)); }
// Find any path between the two nodes. Return the path's total cost. public int FindAnyPath(NetworkNode fromNode, NetworkNode toNode, out List <NetworkNode> pathNodes, out List <NetworkLink> pathLinks) { // Make a spanning tree. bool isConnected; MakeSpanningTree(fromNode, out isConnected); // Follow the tree's links back from toNode to fromNode. return(FindSpanningTreePath(fromNode, toNode, out pathNodes, out pathLinks)); }
// Return true if a neighbor has the indicated color. public bool NeighborHasColor(Color color) { foreach (NetworkLink link in Links) { NetworkNode neighbor = link.Nodes[1]; if (neighbor.IsColored && (neighbor.BackColor == color)) { return(true); } } return(false); }
// Make a link between the two nodes. public NetworkLink(NetworkNode node0, NetworkNode node1) { Nodes[0] = node0; Nodes[1] = node1; float dx = node0.Location.X - node1.Location.X; float dy = node0.Location.Y - node1.Location.Y; Cost = (int)Math.Sqrt(dx * dx + dy * dy); Capacity = Rand.Next(1, 3) + Rand.Next(0, 3); node0.Links.Add(this); }
// Craete a network from a network file. public static Network LoadNetwork(string filename) { // Make a new network. Network network = new Network(); // Read the data. string[] allLines = File.ReadAllLines(filename); // Get the number of nodes. int numNodes = int.Parse(allLines[0]); // Create the nodes. for (int i = 0; i < numNodes; i++) { network.AllNodes.Add(new NetworkNode()); network.AllNodes[i].Index = i; } // Read the nodes. char[] separators = { ',' }; for (int i = 1; i < allLines.Length; i++) { NetworkNode node = network.AllNodes[i - 1]; string[] nodeFields = allLines[i].Split(separators); // Get the node's text and coordinates. node.Name = nodeFields[0]; node.Location = new PointF( int.Parse(nodeFields[1]), int.Parse(nodeFields[2]) ); // Get the node's links. for (int j = 3; j < nodeFields.Length; j += 3) { // Get the next link. NetworkLink link = new NetworkLink(); link.Nodes[0] = node; int index = int.Parse(nodeFields[j]); link.Nodes[1] = network.AllNodes[index]; link.Cost = int.Parse(nodeFields[j + 1]); link.Capacity = int.Parse(nodeFields[j + 2]); node.Links.Add(link); } } return(network); }
private void allPairsToolStripButton_Click(object sender, EventArgs e) { // Find all pairs shortest paths. int[,] distance; int[,] via; TheNetwork.FindAllPairsPaths(out distance, out via); // Display the arrays. Console.WriteLine("Final arrays:"); Console.WriteLine("distance:"); Console.WriteLine(ArrayToString(distance, false)); Console.WriteLine("via:"); Console.WriteLine(ArrayToString(via, true)); // Display all of the paths. int N = TheNetwork.AllNodes.Count; for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { List <NetworkNode> path = TheNetwork.FindAllPairsPath(distance, via, i, j); NetworkNode startNode = TheNetwork.AllNodes[i]; NetworkNode endNode = TheNetwork.AllNodes[j]; Console.Write(startNode.Name + " --> " + endNode.Name + " [" + distance[i, j] + "] : "); if (path == null) { Console.WriteLine("No path"); } else { foreach (NetworkNode viaNode in path) { Console.Write(viaNode.Name + " "); } Console.WriteLine(""); } } } Console.WriteLine(""); MessageBox.Show("See the Output Window for results."); }
// Add a link to the indicated node. public void AddLinkTo(NetworkNode node) { new NetworkLink(this, node); }
// Find a shortest path tree rooted at fromNode // by using a label correcting algorithm. // Return the tree's total cost. public int FindLabelCorrectingPathTree(NetworkNode fromNode) { // Reset the network. ResetNetwork(); // Set all nodes' distances to infinity and their labels to 0. foreach (NetworkNode node in AllNodes) { node.Distance = int.MaxValue; node.Text = "0"; } // Add the start node to the shortest path tree. fromNode.Visited = true; fromNode.Distance = 0; // Make the candidate list. Queue <NetworkLink> candidateLinks = new Queue <NetworkLink>(); // Add the start node's links to the candidate list. foreach (NetworkLink link in fromNode.Links) { candidateLinks.Enqueue(link); } // Make a shortest path tree. while (candidateLinks.Count > 0) { // Use the first link in the candidate list. NetworkLink link = candidateLinks.Dequeue(); // See if link this improves its destination node's distance. int newDistance = link.Nodes[0].Distance + link.Cost; NetworkNode toNode = link.Nodes[1]; if (newDistance < toNode.Distance) { // This is an improvement. // Update the node's distance. toNode.Distance = newDistance; // Update the node's FromNode and FromLink. toNode.FromNode = link.Nodes[0]; toNode.FromLink = link; // Update the node's label. int numUpdates = int.Parse(toNode.Text); numUpdates++; toNode.Text = numUpdates.ToString(); // Add the node's links to the candidate list. foreach (NetworkLink newLink in toNode.Links) { candidateLinks.Enqueue(newLink); } } } // Set the Visited properties for the visited nodes and links. int cost = 0; foreach (NetworkNode node in AllNodes) { node.Visited = true; if (node.FromLink != null) { node.FromLink.Visited = true; cost += node.FromLink.Cost; } } // Return the total cost. return(cost); }
// Follow a spanning tree's links to find a path from fromNode to toNode. public int FindSpanningTreePath(NetworkNode fromNode, NetworkNode toNode, out List <NetworkNode> pathNodes, out List <NetworkLink> pathLinks) { // Follow the tree's links back from toNode to fromNode. pathNodes = new List <NetworkNode>(); pathLinks = new List <NetworkLink>(); NetworkNode currentNode = toNode; while (currentNode != fromNode) { // Add this node to the path. pathNodes.Add(currentNode); // Find the previous node. NetworkNode prevNode = currentNode.FromNode; // Find the link that leads to currentNode. NetworkLink prevLink = null; foreach (NetworkLink link in prevNode.Links) { if (link.Nodes[1] == currentNode) { prevLink = link; break; } } // Make sure we found the link. Debug.Assert(prevLink != null); // Add the link to the path. pathLinks.Add(prevLink); // Move to the next node. currentNode = prevNode; } // while (currentNode != fromNode) // Add the start node. pathNodes.Add(fromNode); // Reverse the order of the nodes and links. pathNodes.Reverse(); pathLinks.Reverse(); // Unmark all nodes and links. DeselectNodes(); DeselectBranches(); // Marks the path's nodes and links. foreach (NetworkNode node in pathNodes) { node.Visited = true; } foreach (NetworkLink link in pathLinks) { link.Visited = true; } // Calculate the cost of the path. int cost = 0; foreach (NetworkLink link in pathLinks) { cost += link.Cost; } // Return the cost. return(cost); }
// Find a shortest path tree rooted at fromNode // by using a label setting algorithm. // Return the tree's total cost. public int FindLabelSettingPathTree(NetworkNode fromNode) { // Reset the network. ResetNetwork(); // Keep track of the number of nodes in the tree. int numDone = 0; // Add the start node to the shortest path tree. fromNode.Visited = true; fromNode.Distance = 0; fromNode.Text = numDone.ToString(); numDone++; // Track the tree's total cost. int cost = 0; // Make the candidate list. List <NetworkLink> candidateLinks = new List <NetworkLink>(); // Add the start node's links to the candidate list. foreach (NetworkLink link in fromNode.Links) { candidateLinks.Add(link); } // Make a shortest path tree. while (candidateLinks.Count > 0) { // Find the best link. NetworkLink bestLink = null; int bestCost = int.MaxValue; for (int i = candidateLinks.Count - 1; i >= 0; i--) { NetworkLink testLink = candidateLinks[i]; // See if the link leads outside the tree. if (testLink.Nodes[1].Visited) { // Remove this link. candidateLinks.RemoveAt(i); } else { // See if this link is an improvement. int testCost = testLink.Nodes[0].Distance + testLink.Cost; if (testCost < bestCost) { bestCost = testCost; bestLink = testLink; } } } // If we found no link, then the candidate // list must be empty and we're done. if (bestLink == null) { Debug.Assert(candidateLinks.Count == 0); break; } // Use this link. // Remove it from the candidate list. candidateLinks.Remove(bestLink); // Add the node to the tree. NetworkNode bestNode = bestLink.Nodes[1]; bestNode.Distance = bestLink.Nodes[0].Distance + bestLink.Cost; bestNode.Visited = true; bestLink.Visited = true; bestNode.FromNode = bestLink.Nodes[0]; bestNode.Text = numDone.ToString(); numDone++; // Add the node's links to the tree. foreach (NetworkLink newLink in bestNode.Links) { if (!newLink.Nodes[1].Visited) { candidateLinks.Add(newLink); } } // Add the link's cost to the tree's total cost. cost += bestLink.Cost; } // Return the total cost. return(cost); }
// Build a minimal spanning tree. Return its total cost. // When it adds a node to the spanning tree, the algorithm // also adds its links that lead outside of the tree to a list. // Later it searches that list for a minimal link. public int MakeMinimalSpanningTree(NetworkNode root, out bool isConnected) { // Reset the network. ResetNetwork(); // The total cost of the links in the spanning tree. int totalCost = 0; // Add the root node's links to the link candidate list. List <NetworkLink> candidateLinks = new List <NetworkLink>(); foreach (NetworkLink link in root.Links) { candidateLinks.Add(link); } // Visit the root node. root.Visited = true; // Process the list until it's empty. while (candidateLinks.Count > 0) { // Find the link with the lowest cost. NetworkLink bestLink = candidateLinks[0]; int bestCost = bestLink.Cost; for (int i = 1; i < candidateLinks.Count; i++) { if (candidateLinks[i].Cost < bestCost) { // Save this improvement. bestLink = candidateLinks[i]; bestCost = bestLink.Cost; } } // Remove the link from the list. candidateLinks.Remove(bestLink); // Get the node at the other end of the link. NetworkNode toNode = bestLink.Nodes[1]; // See if the link's node is still unmarked. if (!toNode.Visited) { // Use the link. bestLink.Visited = true; totalCost += bestLink.Cost; toNode.Visited = true; // Record the node that got us here. toNode.FromNode = bestLink.Nodes[0]; // Process toNode's links. foreach (NetworkLink newLink in toNode.Links) { // If the node hasn't been visited, // add the link to the list. if (!newLink.Nodes[1].Visited) { candidateLinks.Add(newLink); } } } } // See if the network is connected. isConnected = true; foreach (NetworkNode node in AllNodes) { if (!node.Visited) { isConnected = false; break; } } return(totalCost); }
// Build a spanning tree. Return its total cost. public int MakeSpanningTree(NetworkNode root, out bool isConnected) { // Reset the network. ResetNetwork(); // The total cost of the links in the spanning tree. int totalCost = 0; // Push the root node onto the stack. Stack <NetworkNode> stack = new Stack <NetworkNode>(); stack.Push(root); // Visit the root node. root.Visited = true; // Process the stack until it's empty. while (stack.Count > 0) { // Get the next node from the stack. NetworkNode node = stack.Pop(); // Process the node's links. foreach (NetworkLink link in node.Links) { // Only use the link if the destination // node hasn't been visited. NetworkNode toNode = link.Nodes[1]; if (!toNode.Visited) { // Mark the node as visited. toNode.Visited = true; // Record the node that got us here. toNode.FromNode = node; // Mark the link as part of the tree. link.Visited = true; // Push the node onto the stack. stack.Push(toNode); // Add the link's cost to the total cost. totalCost += link.Cost; } } } // See if the network is connected. isConnected = true; foreach (NetworkNode node in AllNodes) { if (!node.Visited) { isConnected = false; break; } } return(totalCost); }
// Return the network's connected components. public List <List <NetworkNode> > GetConnectedComponents() { // Reset the network. ResetNetwork(); // Keep track of the number of nodes visited. int numVisited = 0; // Make the result list of lists. List <List <NetworkNode> > components = new List <List <NetworkNode> >(); // Repeat until all nodes are in a connected component. while (numVisited < AllNodes.Count) { // Find a node that hasn't been visited. NetworkNode startNode = null; foreach (NetworkNode node in AllNodes) { if (!node.Visited) { startNode = node; break; } } // Make sure we found one. Debug.Assert(startNode != null); // Add the start node to the stack. Stack <NetworkNode> stack = new Stack <NetworkNode>(); stack.Push(startNode); startNode.Visited = true; numVisited++; // Add the node to a new connected component. List <NetworkNode> component = new List <NetworkNode>(); components.Add(component); component.Add(startNode); // Process the stack until it's empty. while (stack.Count > 0) { // Get the next node from the stack. NetworkNode node = stack.Pop(); // Process the node's links. foreach (NetworkLink link in node.Links) { // Only use the link if the destination // node hasn't been visited. NetworkNode toNode = link.Nodes[1]; if (!toNode.Visited) { // Mark the node as visited. toNode.Visited = true; // Mark the link as part of the tree. link.Visited = true; numVisited++; // Add the node to the current connected component. component.Add(toNode); // Push the node onto the stack. stack.Push(toNode); } } } } // Return the components. return(components); }
// Traverse the network in breadth-first order. public List <NetworkNode> BreadthFirstTraverse(NetworkNode startNode, out bool isConnected) { // Reset the network. ResetNetwork(); // Keep track of the number of nodes in the traversal. int numDone = 0; // Add the start node to the queue. Queue <NetworkNode> queue = new Queue <NetworkNode>(); queue.Enqueue(startNode); // Visit the start node. List <NetworkNode> traversal = new List <NetworkNode>(); traversal.Add(startNode); startNode.Visited = true; startNode.Text = numDone.ToString(); numDone++; // Process the queue until it's empty. while (queue.Count > 0) { // Get the next node from the queue. NetworkNode node = queue.Dequeue(); // Process the node's links. foreach (NetworkLink link in node.Links) { NetworkNode toNode = link.Nodes[1]; // Only use the link if the destination // node hasn't been visited. if (!toNode.Visited) { // Mark the node as visited. toNode.Visited = true; toNode.Text = numDone.ToString(); numDone++; // Add the node to the traversal. traversal.Add(toNode); // Add the link to the traversal. link.Visited = true; // Add the node onto the queue. queue.Enqueue(toNode); } } } // See if the network is connected. isConnected = true; foreach (NetworkNode node in AllNodes) { if (!node.Visited) { isConnected = false; break; } } return(traversal); }
// Make links from node0 to node1 and node1 to node0. public void MakeLinks(NetworkNode node0, NetworkNode node1) { new NetworkLink(node0, node1); new NetworkLink(node1, node0); }
// Add a node or link if appropriate. private void networkPictureBox_MouseClick(object sender, MouseEventArgs e) { if (Mode == Modes.AddNode) { // Add a node. NetworkNode node = new NetworkNode(); node.Location = e.Location; node.Index = TheNetwork.AllNodes.Count; node.Name = NumberToLetters(node.Index); TheNetwork.AllNodes.Add(node); networkPictureBox.Refresh(); } else if ( (Mode == Modes.AddLink1) || (Mode == Modes.AddLink2)) { // Add a link. // See if there is a node here. NetworkNode node = TheNetwork.FindNode(e.Location); if (node == null) { SystemSounds.Beep.Play(); } else { if (e.Button == MouseButtons.Left) { Node0 = node; } else { Node1 = node; } // See if we have both nodes. if ((Node0 != null) && (Node1 != null)) { // Make the link. if (Mode == Modes.AddLink1) { TheNetwork.MakeLink(Node0, Node1); } else { TheNetwork.MakeLinks(Node0, Node1); } // We're done with this link. Node0 = null; Node1 = null; // Redraw. networkPictureBox.Refresh(); } } } else if (Mode == Modes.DFTraversal) { // See if there is a node here. NetworkNode node = TheNetwork.FindNode(e.Location); if (node == null) { SystemSounds.Beep.Play(); } else { // Traverse the network. bool isConnected; List <NetworkNode> traversal = TheNetwork.DepthFirstTraverse(node, out isConnected); // Display the traversal. string txt = ""; foreach (NetworkNode traversalNode in traversal) { txt += " " + traversalNode.ToString(); } toolStripStatusLabel1.Text = "Traversal: " + txt; if (isConnected) { txt += " Connected."; } else { txt += " Not connected."; } toolStripStatusLabel1.Text = txt; Console.WriteLine(txt); // Redraw the network. networkPictureBox.Refresh(); } } else if (Mode == Modes.BFTraversal) { // See if there is a node here. NetworkNode node = TheNetwork.FindNode(e.Location); if (node == null) { SystemSounds.Beep.Play(); } else { // Traverse the network. bool isConnected; List <NetworkNode> traversal = TheNetwork.BreadthFirstTraverse(node, out isConnected); // Display the traversal. string txt = ""; foreach (NetworkNode traversalNode in traversal) { txt += " " + traversalNode.ToString(); } toolStripStatusLabel1.Text = "Traversal: " + txt; if (isConnected) { txt += " Connected."; } else { txt += " Not connected."; } toolStripStatusLabel1.Text = txt; Console.WriteLine(txt); // Redraw the network. networkPictureBox.Refresh(); } } else if (Mode == Modes.SpanningTree) { // See if there is a node here. NetworkNode node = TheNetwork.FindNode(e.Location); if (node == null) { SystemSounds.Beep.Play(); } else { // Build a spanning tree. bool isConnected; float cost = TheNetwork.MakeSpanningTree(node, out isConnected); toolStripStatusLabel1.Text = "Total cost: " + cost.ToString(); string txt; if (isConnected) { txt = "Connected. "; } else { txt = "Not connected. "; } txt += "Total cost: " + cost.ToString(); toolStripStatusLabel1.Text = txt; Console.WriteLine(txt); // Redraw the network. networkPictureBox.Refresh(); } } else if (Mode == Modes.MinimalSpanningTree) { // See if there is a node here. NetworkNode node = TheNetwork.FindNode(e.Location); if (node == null) { SystemSounds.Beep.Play(); } else { // Build a spanning tree. bool isConnected; float cost = TheNetwork.MakeMinimalSpanningTree(node, out isConnected); string txt; if (isConnected) { txt = "Connected. "; } else { txt = "Not connected. "; } txt += "Total cost: " + cost.ToString(); toolStripStatusLabel1.Text = txt; Console.WriteLine(txt); // Redraw the network. networkPictureBox.Refresh(); } } else if (Mode == Modes.AnyPath) { // See if there is a node here. NetworkNode node = TheNetwork.FindNode(e.Location); if (node == null) { SystemSounds.Beep.Play(); } else { if (e.Button == MouseButtons.Left) { Node0 = node; } else { Node1 = node; } // See if we have both nodes. if ((Node0 != null) && (Node1 != null)) { // Find a path between the nodes. List <NetworkNode> pathNodes; List <NetworkLink> pathLinks; int cost = TheNetwork.FindAnyPath(Node0, Node1, out pathNodes, out pathLinks); string txt = "Path: "; foreach (NetworkNode pathNode in pathNodes) { txt += pathNode.Name + " "; } txt += "Total cost: " + cost.ToString(); toolStripStatusLabel1.Text = txt; Console.WriteLine(txt); // Redraw the network. networkPictureBox.Refresh(); } } } else if (Mode == Modes.LabelSettingTree) { // See if there is a node here. NetworkNode node = TheNetwork.FindNode(e.Location); if (node == null) { SystemSounds.Beep.Play(); } else { // Build a label setting shortest path tree. float cost = TheNetwork.FindLabelSettingPathTree(node); string txt = "Total cost: " + cost.ToString(); toolStripStatusLabel1.Text = txt; Console.WriteLine(txt); // Redraw the network. networkPictureBox.Refresh(); } } else if (Mode == Modes.LabelSettingPath) { // See if there is a node here. NetworkNode node = TheNetwork.FindNode(e.Location); if (node == null) { SystemSounds.Beep.Play(); } else { if (e.Button == MouseButtons.Left) { Node0 = node; } else { Node1 = node; } // See if we have both nodes. if ((Node0 != null) && (Node1 != null)) { // Find a path between the nodes. List <NetworkNode> pathNodes; List <NetworkLink> pathLinks; int cost = TheNetwork.FindLabelSettingPath(Node0, Node1, out pathNodes, out pathLinks); string txt = "Path: "; foreach (NetworkNode pathNode in pathNodes) { txt += pathNode.Name + " "; } txt += "Total cost: " + cost.ToString(); toolStripStatusLabel1.Text = txt; Console.WriteLine(txt); // Redraw the network. networkPictureBox.Refresh(); } } } else if (Mode == Modes.LabelCorrectingTree) { // See if there is a node here. NetworkNode node = TheNetwork.FindNode(e.Location); if (node == null) { SystemSounds.Beep.Play(); } else { // Build a label setting shortest path tree. float cost = TheNetwork.FindLabelCorrectingPathTree(node); string txt = "Total cost: " + cost.ToString(); toolStripStatusLabel1.Text = txt; Console.WriteLine(txt); // Redraw the network. networkPictureBox.Refresh(); } } else if (Mode == Modes.LabelCorrectingPath) { // See if there is a node here. NetworkNode node = TheNetwork.FindNode(e.Location); if (node == null) { SystemSounds.Beep.Play(); } else { if (e.Button == MouseButtons.Left) { Node0 = node; } else { Node1 = node; } // See if we have both nodes. if ((Node0 != null) && (Node1 != null)) { // Find a path between the nodes. List <NetworkNode> pathNodes; List <NetworkLink> pathLinks; int cost = TheNetwork.FindLabelCorrectingPath(Node0, Node1, out pathNodes, out pathLinks); string txt = "Path: "; foreach (NetworkNode pathNode in pathNodes) { txt += pathNode.Name + " "; } txt += "Total cost: " + cost.ToString(); toolStripStatusLabel1.Text = txt; Console.WriteLine(txt); // Redraw the network. networkPictureBox.Refresh(); } } } else if (Mode == Modes.MaximalFlow) { // See if there is a node here. NetworkNode node = TheNetwork.FindNode(e.Location); if (node == null) { SystemSounds.Beep.Play(); } else { if (e.Button == MouseButtons.Left) { Node0 = node; } else { Node1 = node; } // See if we have both nodes. if ((Node0 != null) && (Node1 != null)) { // Calculate the maximal flow. int flow = TheNetwork.MaximalFlow(Node0, Node1); // Redraw. networkPictureBox.Refresh(); // Display the result. string txt = "Total flow " + Node0.ToString() + "-->" + Node1.ToString() + ": " + flow; Console.WriteLine(txt); MessageBox.Show(txt); // We're done with these nodes. Node0 = null; Node1 = null; } } } else if (Mode == Modes.MinFlowCut) { // See if there is a node here. NetworkNode node = TheNetwork.FindNode(e.Location); if (node == null) { SystemSounds.Beep.Play(); } else { if (e.Button == MouseButtons.Left) { Node0 = node; } else { Node1 = node; } // See if we have both nodes. if ((Node0 != null) && (Node1 != null)) { // Find a minimal flow cut. int flow = TheNetwork.MinimalFlowCut(Node0, Node1); // Redraw. networkPictureBox.Refresh(); // Display the result. string txt = "Minimal flow cut " + Node0.ToString() + "-->" + Node1.ToString() + ": " + flow; Console.WriteLine(txt); MessageBox.Show(txt); // We're done with these nodes. Node0 = null; Node1 = null; } } } }