// This uses Prim's algorithm: "https://en.wikipedia.org/wiki/Prim's_algorithm. We don't actually need // to build the MST, just need the total cost of the streets that compose it. The heap itself can be // used to keep track of which vertices are in the MST. Arbitrarily choose the building/vertex with ID 0 // to begin creating the MST from. Using int.MaxValue as a sentinel value to represent the street cost // for a building into the growing MST when that building actually has no street into the MST. Hopefully // that doesn't lead to problems, otherwise would need nullable ints w/ a custom comparer, or something. public static long Solve(int buildingCount, int[,] streets) { var buildingGraph = WeightedSimpleGraph.CreateFromOneBasedEdges(buildingCount, streets); var connectionCosts = new BinaryHeap(buildingGraph, buildingGraph.Vertices[0]); long totalStreetCost = 0; while (!connectionCosts.IsEmpty) { var cheapestConnection = connectionCosts.Extract(); var building = cheapestConnection.Key; int costToConnectBuilding = cheapestConnection.Value; totalStreetCost += costToConnectBuilding; foreach (var neighbor in building.Neighbors) { int costToConnectNeighborFromBuilding = building.GetEdgeWeight(neighbor); int currentCostToConnectNeighbor; // The neighboring building may still be in the heap, or it might already be in the MST. If // it's still in the heap, check to see if we can improve its cost to get into the MST by // utilizing its street to the building just added. if (connectionCosts.TryGetValue(neighbor, out currentCostToConnectNeighbor)) { if (costToConnectNeighborFromBuilding < currentCostToConnectNeighbor) { connectionCosts.Update(neighbor, costToConnectNeighborFromBuilding); } } } } return(totalStreetCost); }
public void ValidatesAGraph2() { // This graph is two lines and a point. var graph = WeightedSimpleGraph <int> .CreateFromOneBasedEdges(5, new[, ] { { 1, 2, 10 }, { 3, 4, 11 } }); Assert.AreEqual(1, graph.Vertices[0].Degree); Assert.AreEqual(1, graph.Vertices[1].Degree); Assert.AreEqual(1, graph.Vertices[2].Degree); Assert.AreEqual(1, graph.Vertices[3].Degree); Assert.AreEqual(0, graph.Vertices[4].Degree); Assert.IsTrue(graph.HasEdge(0, 1)); Assert.IsTrue(graph.HasEdge(2, 3)); Assert.IsFalse(graph.HasEdge(2, 0)); Assert.IsFalse(graph.HasEdge(0, 3)); Assert.IsFalse(graph.HasEdge(1, 2)); Assert.IsFalse(graph.HasEdge(3, 1)); for (int i = 0; i <= 4; ++i) { Assert.IsFalse(graph.HasEdge(4, i)); } Assert.IsFalse(graph.Vertices[0].HasNeighbor(0)); Assert.IsTrue(graph.Vertices[0].HasNeighbor(1)); Assert.IsFalse(graph.Vertices[0].HasNeighbor(2)); Assert.IsFalse(graph.Vertices[0].HasNeighbor(3)); Assert.IsFalse(graph.Vertices[0].HasNeighbor(4)); Assert.IsTrue(graph.Vertices[1].HasNeighbor(0)); Assert.IsFalse(graph.Vertices[1].HasNeighbor(1)); Assert.IsFalse(graph.Vertices[1].HasNeighbor(2)); Assert.IsFalse(graph.Vertices[1].HasNeighbor(3)); Assert.IsFalse(graph.Vertices[1].HasNeighbor(4)); Assert.IsFalse(graph.Vertices[2].HasNeighbor(0)); Assert.IsFalse(graph.Vertices[2].HasNeighbor(1)); Assert.IsFalse(graph.Vertices[2].HasNeighbor(2)); Assert.IsTrue(graph.Vertices[2].HasNeighbor(3)); Assert.IsFalse(graph.Vertices[2].HasNeighbor(4)); Assert.IsFalse(graph.Vertices[3].HasNeighbor(0)); Assert.IsFalse(graph.Vertices[3].HasNeighbor(1)); Assert.IsTrue(graph.Vertices[3].HasNeighbor(2)); Assert.IsFalse(graph.Vertices[3].HasNeighbor(3)); Assert.IsFalse(graph.Vertices[3].HasNeighbor(4)); Assert.IsFalse(graph.Vertices[4].HasNeighbor(0)); Assert.IsFalse(graph.Vertices[4].HasNeighbor(1)); Assert.IsFalse(graph.Vertices[4].HasNeighbor(2)); Assert.IsFalse(graph.Vertices[4].HasNeighbor(3)); Assert.IsFalse(graph.Vertices[4].HasNeighbor(4)); Assert.AreEqual(10, graph.Vertices[0].GetEdgeWeight(1)); Assert.AreEqual(11, graph.Vertices[2].GetEdgeWeight(3)); }