Skip to content

Commit 94666ff

Browse files
committed
Added Bellman, FW and Johnsons
1 parent d0568f6 commit 94666ff

File tree

10 files changed

+446
-101
lines changed

10 files changed

+446
-101
lines changed

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Algos in Python
22
======
33

4-
Implementation for the algorithms and datastructures taught in [CS161](http://openclassroom.stanford.edu/MainFolder/CoursePage.php?course=IntroToAlgorithms), in Python
4+
Implementations of a few algorithms and datastructures for fun and profit!
55

66
Completed
77
---
@@ -20,6 +20,9 @@ Completed
2020
- Prim's Minimum Cost Spanning Tree - O(mlogn)
2121
- Kruskal's Minimum Spanning Tree - O(mlogn)
2222
- Max k Clustering
23+
- Bellman Ford
24+
- Floyd Warshall
25+
- Johnson's Algorithm
2326
- Heap datastructure
2427
- Max heaps
2528
- Min heaps (priority queue)

dp/bellman_ford.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
""" The bellman ford algorithm for calculating single source shortest
2+
paths - CLRS style """
3+
graph = {
4+
's' : {'t':6, 'y':7},
5+
't' : {'x':5, 'z':-4, 'y':8 },
6+
'y' : {'z':9, 'x':-3},
7+
'z' : {'x':7, 's': 2},
8+
'x' : {'t':-2}
9+
}
10+
11+
INF = float('inf')
12+
13+
dist = {}
14+
predecessor = {}
15+
16+
def initialize_single_source(graph, s):
17+
for v in graph:
18+
dist[v] = INF
19+
predecessor[v] = None
20+
dist[s] = 0
21+
22+
def relax(graph, u, v):
23+
if dist[v] > dist[u] + graph[u][v]:
24+
dist[v] = dist[u] + graph[u][v]
25+
predecessor[v] = u
26+
27+
def bellman_ford(graph, s):
28+
initialize_single_source(graph, s)
29+
edges = [(u, v) for u in graph for v in graph[u].keys()]
30+
number_vertices = len(graph)
31+
for i in range(number_vertices-1):
32+
for (u, v) in edges:
33+
relax(graph, u, v)
34+
for (u, v) in edges:
35+
if dist[v] > dist[u] + graph[u][v]:
36+
return False # there exists a negative cycle
37+
return True
38+
39+
def get_distances(graph, s):
40+
if bellman_ford(graph, s):
41+
return dist
42+
return "Graph contains a negative cycle"
43+
44+
print get_distances(graph, 's')

dp/dijkstra.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
from heapq import heappush, heappop
2+
# graph = {
3+
# 's' : {'t':6, 'y':7},
4+
# 't' : {'x':5, 'z':4, 'y':8 },
5+
# 'y' : {'z':9, 'x':3},
6+
# 'z' : {'x':7, 's': 2},
7+
# 'x' : {'t':2}
8+
# }
9+
10+
def read_graph(file):
11+
graph = dict()
12+
with open(file) as f:
13+
for l in f:
14+
(u, v, w) = l.split()
15+
if int(u) not in graph:
16+
graph[int(u)] = dict()
17+
graph[int(u)][int(v)] = int(w)
18+
return graph
19+
20+
inf = float('inf')
21+
def dijkstra(graph, s):
22+
n = len(graph.keys())
23+
dist = dict()
24+
Q = list()
25+
26+
for v in graph:
27+
dist[v] = inf
28+
dist[s] = 0
29+
30+
heappush(Q, (dist[s], s))
31+
32+
while Q:
33+
d, u = heappop(Q)
34+
if d < dist[u]:
35+
dist[u] = d
36+
for v in graph[u]:
37+
if dist[v] > dist[u] + graph[u][v]:
38+
dist[v] = dist[u] + graph[u][v]
39+
heappush(Q, (dist[v], v))
40+
return dist
41+
42+
graph = read_graph("graph.txt")
43+
print dijkstra(graph, 1)

dp/floyd.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
""" Floyd warshall in numpy and standard implementation """
2+
from numpy import *
3+
inf = float('inf')
4+
graph = [
5+
[0, 3, 8, inf, -4],
6+
[inf, 0, inf, 1, 7],
7+
[inf, 4, 0, inf, inf],
8+
[2, inf, -5, 0, inf],
9+
[inf, inf, inf, 6, 0]
10+
]
11+
12+
def make_matrix(file, n):
13+
graph = [[inf for i in range(n)] for i in range(n)]
14+
with open(file) as f:
15+
for l in f:
16+
(i, j, w) = l.split()
17+
graph[int(i)-1][int(j)-1] = int(w)
18+
return graph
19+
20+
def floyd_warshall(graph):
21+
n = len(graph)
22+
D = graph
23+
for k in range(n):
24+
for i in range(n):
25+
for j in range(n):
26+
if i==j:
27+
D[i][j] = 0
28+
else:
29+
D[i][j] = min(D[i][j], D[i][k] + D[k][j])
30+
return D
31+
32+
def fastfloyd(D):
33+
_,n = D.shape
34+
for k in xrange(n):
35+
i2k = reshape(D[k,:],(1,n))
36+
k2j = reshape(D[:,k],(n,1))
37+
D = minimum(D,i2k+k2j)
38+
return D.min() if not any(D.diagonal() < 0) else None
39+
40+
def get_min_dist(D):
41+
if negative_cost_cycle(D):
42+
return "Negative cost cycle"
43+
return min(i for d in D for i in d)
44+
45+
def negative_cost_cycle(D):
46+
n = len(D)
47+
for i in range(n):
48+
if D[i][i] < 0:
49+
return True
50+
return False
51+
52+
# print get_min_dist(floyd_warshall(graph))
53+
n = 1000
54+
gr = make_matrix("g1.txt", n)
55+
#D = floyd_warshall(gr)
56+
print fastfloyd(array(gr))
57+
# print get_min_dist(D)
58+
# print D

dp/johnsons_apsp.py

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
from heapq import heappush, heappop
2+
from datetime import datetime
3+
from copy import deepcopy
4+
graph = {
5+
'a' : {'b':-2},
6+
'b' : {'c':-1},
7+
'c' : {'x':2, 'a':4, 'y':-3},
8+
'z' : {'x':1, 'y':-4},
9+
'x' : {},
10+
'y' : {},
11+
}
12+
13+
inf = float('inf')
14+
dist = {}
15+
16+
def read_graph(file,n):
17+
graph = dict()
18+
with open(file) as f:
19+
for l in f:
20+
(u, v, w) = l.split()
21+
if int(u) not in graph:
22+
graph[int(u)] = dict()
23+
graph[int(u)][int(v)] = int(w)
24+
for i in range(n):
25+
if i not in graph:
26+
graph[i] = dict()
27+
return graph
28+
29+
def dijkstra(graph, s):
30+
n = len(graph.keys())
31+
dist = dict()
32+
Q = list()
33+
34+
for v in graph:
35+
dist[v] = inf
36+
dist[s] = 0
37+
38+
heappush(Q, (dist[s], s))
39+
40+
while Q:
41+
d, u = heappop(Q)
42+
if d < dist[u]:
43+
dist[u] = d
44+
for v in graph[u]:
45+
if dist[v] > dist[u] + graph[u][v]:
46+
dist[v] = dist[u] + graph[u][v]
47+
heappush(Q, (dist[v], v))
48+
return dist
49+
50+
def initialize_single_source(graph, s):
51+
for v in graph:
52+
dist[v] = inf
53+
dist[s] = 0
54+
55+
def relax(graph, u, v):
56+
if dist[v] > dist[u] + graph[u][v]:
57+
dist[v] = dist[u] + graph[u][v]
58+
59+
def bellman_ford(graph, s):
60+
initialize_single_source(graph, s)
61+
edges = [(u, v) for u in graph for v in graph[u].keys()]
62+
number_vertices = len(graph)
63+
for i in range(number_vertices-1):
64+
for (u, v) in edges:
65+
relax(graph, u, v)
66+
for (u, v) in edges:
67+
if dist[v] > dist[u] + graph[u][v]:
68+
return False # there exists a negative cycle
69+
return True
70+
71+
def add_extra_node(graph):
72+
graph[0] = dict()
73+
for v in graph.keys():
74+
if v != 0:
75+
graph[0][v] = 0
76+
77+
def reweighting(graph_new):
78+
add_extra_node(graph_new)
79+
if not bellman_ford(graph_new, 0):
80+
# graph contains negative cycles
81+
return False
82+
for u in graph_new:
83+
for v in graph_new[u]:
84+
if u != 0:
85+
graph_new[u][v] += dist[u] - dist[v]
86+
del graph_new[0]
87+
return graph_new
88+
89+
def johnsons(graph_new):
90+
graph = reweighting(graph_new)
91+
if not graph:
92+
return False
93+
final_distances = {}
94+
for u in graph:
95+
final_distances[u] = dijkstra(graph, u)
96+
97+
for u in final_distances:
98+
for v in final_distances[u]:
99+
final_distances[u][v] += dist[v] - dist[u]
100+
return final_distances
101+
102+
def compute_min(final_distances):
103+
return min(final_distances[u][v] for u in final_distances for v in final_distances[u])
104+
105+
if __name__ == "__main__":
106+
# graph = read_graph("graph.txt", 1000)
107+
graph_new = deepcopy(graph)
108+
t1 = datetime.utcnow()
109+
final_distances = johnsons(graph_new)
110+
if not final_distances:
111+
print "Negative cycle"
112+
else:
113+
print compute_min(final_distances)
114+
print datetime.utcnow() - t1

dp/kpdata2.txt

Lines changed: 0 additions & 100 deletions
This file was deleted.

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy