-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathWeightedGraph.cs
More file actions
213 lines (171 loc) · 7.53 KB
/
WeightedGraph.cs
File metadata and controls
213 lines (171 loc) · 7.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
using CSharp.DS.Heap;
using CSharp.DS.UnionFind;
using System;
using System.Collections.Generic;
using System.Linq;
namespace CSharp.DS.Graph
{
/// <summary>
/// Directed weighted Graph representation as a disjoint set of weighted edges
/// Useful to model shortest path and minimum cost problems
/// </summary>
public class WeightedGraph<T>
{
public class Vertex
{
public T val;
public Vertex(T val)
{
this.val = val;
}
}
public class Edge
{
public Vertex source, destination;
public int weight;
public Edge(Vertex source, Vertex destination, int weight)
{
this.source = source;
this.destination = destination;
this.weight = weight;
}
};
/// <summary>
/// Helper data structure for Prim and Dijstra
/// </summary>
public class PathCost : IComparable
{
public Vertex vertex;
public int cost;
public PathCost(Vertex vertex, int cost)
{
this.vertex = vertex;
this.cost = cost;
}
public int CompareTo(object obj)
{
if (!(obj is PathCost pathCost))
{
return -1;
}
return this.cost.CompareTo(pathCost.cost);
}
}
public Dictionary<Vertex, LinkedList<Edge>> adjacencyList;
public WeightedGraph()
{
adjacencyList = new Dictionary<Vertex, LinkedList<Edge>>();
}
public int VertexesCount => adjacencyList.Count();
public int EdgesCount { get; private set; }
public void AddDirectedEdge(Vertex source, Vertex destination, int weight)
{
if (!adjacencyList.ContainsKey(source))
adjacencyList.Add(source, new LinkedList<Edge>());
if (!adjacencyList.ContainsKey(destination))
adjacencyList.Add(destination, new LinkedList<Edge>());
adjacencyList[source].AddLast(new Edge(source, destination, weight));
EdgesCount++;
}
public List<Edge> KruskalMinimumSpanningTree()
{
var mst = new List<Edge>();
var vertexes = adjacencyList.Keys;
// Edges by increasing order of weight
var edgesByWeight = adjacencyList.Values.SelectMany(e => e).OrderBy(e => e.weight);
// Use a Disjoint Set to keep track of the connected components
var spanningTreeUnion = new UnionFind<Vertex>(vertexes);
// A minimum spanning tree has V–1 edges where V is the number of vertices in the given graph
// Greedy strategy: pick the smallest weight edge that does not cause a cycle in the MST constructed so far
int minSpanningTreeCount = 0;
for (var i = 0; i < edgesByWeight.Count()
&& minSpanningTreeCount < vertexes.Count() - 1; i++)
{
var edge = edgesByWeight.ElementAt(i);
var sourceSubset = spanningTreeUnion.Find(edge.source);
var destinationSubset = spanningTreeUnion.Find(edge.destination);
if (sourceSubset == destinationSubset) // will cause a cycle
continue;
spanningTreeUnion.Union(sourceSubset, destinationSubset);
mst.Add(edge);
minSpanningTreeCount++;
}
return mst;
}
public List<Edge> PrimsMinimumSpanningTree()
{
var mst = new Dictionary<Vertex, Edge>();
if (!adjacencyList.Any())
{
return mst.Values.ToList();
}
var vertexToMinCost = new Dictionary<Vertex, PathCost>();
// Min Heap storing min cost of the spanning tree
var minHeapNodes = new IndexedHeap<PathCost>(
new List<PathCost> {
(vertexToMinCost[adjacencyList.Keys.First()] = new PathCost(adjacencyList.Keys.First(), 0))
}, (p1, p2) => p1.cost.CompareTo(p2.cost));
foreach (var vertex in adjacencyList.Keys.Skip(1))
minHeapNodes.Push(vertexToMinCost[vertex] = new PathCost(vertex, int.MaxValue));
// Traverse the node by min cost
// Greedy strategy: Select the edge that minimize the cost for reaching node from its neighbors
while (minHeapNodes.Any())
{
var minNode = minHeapNodes.Pop();
// Visit all the neighbors and update the corresponding cost
foreach (var edge in adjacencyList[minNode.vertex])
{
// Check that the current cost of reaching the adjacent node is less than the current one
if (minHeapNodes.Contains(vertexToMinCost[edge.destination]) && edge.weight < vertexToMinCost[edge.destination].cost)
{
vertexToMinCost[edge.destination].cost = edge.weight;
mst[edge.destination] = edge;
// Sift up the heap starting from the current index (log n)
minHeapNodes.SiftUp(fromIndex: minHeapNodes.IndexOf(vertexToMinCost[edge.destination]));
}
}
}
return mst.Values.ToList();
}
public List<Edge> DijkstraShortestPath(Vertex source, Vertex destination = default)
{
var sp = new Dictionary<Vertex, Edge>();
if (!adjacencyList.Any())
{
return sp.Values.ToList();
}
var vertexToPathCost = new Dictionary<Vertex, PathCost>();
// Min Heap storing accumulated min cost for reaching target node greedily
var minHeapNodes = new IndexedHeap<PathCost>(
new List<PathCost> { (vertexToPathCost[source] = new PathCost(source, 0)) },
compareFunc: (p1, p2) => p1.cost.CompareTo(p2.cost));
foreach (var vertex in adjacencyList.Keys)
{
if (vertex == source)
continue;
minHeapNodes.Push(vertexToPathCost[vertex] = new PathCost(vertex, int.MaxValue));
}
// Greedy strategy: Select the path that minimized the accumulated cost up to this node
// Traverse the node by min cost
while (minHeapNodes.Any())
{
var minNode = minHeapNodes.Pop();
// Visit all the neighbors and update the corresponding cost
foreach (var edge in adjacencyList[minNode.vertex])
{
// Check that the current cost of reaching the adjacent node is less than the current one
if (minHeapNodes.Contains(vertexToPathCost[edge.destination]) && minNode.cost + edge.weight < vertexToPathCost[edge.destination].cost)
{
vertexToPathCost[edge.destination].cost = minNode.cost + edge.weight;
sp[edge.destination] = edge;
// Sift up the heap starting from the current index (log n)
minHeapNodes.SiftUp(fromIndex: minHeapNodes.IndexOf(vertexToPathCost[edge.destination]));
}
}
if (minNode.vertex.Equals(destination))
break;
}
return sp.Values.ToList();
}
}
}