Skip to content

Added doctest and more explanation about Dijkstra execution. #1014

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Jul 16, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ script:
matrix
networking_flow
other
project_euler
searches
sorts
strings
Expand Down
2 changes: 1 addition & 1 deletion data_structures/hashing/double_hash.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env python3

from .hash_table import HashTable
from hash_table import HashTable
from number_theory.prime_numbers import next_prime, check_prime


Expand Down
2 changes: 1 addition & 1 deletion data_structures/hashing/hash_table_with_linked_list.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from .hash_table import HashTable
from hash_table import HashTable
from collections import deque


Expand Down
Empty file.
2 changes: 1 addition & 1 deletion data_structures/hashing/quadratic_probing.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env python3

from .hash_table import HashTable
from hash_table import HashTable


class QuadraticProbing(HashTable):
Expand Down
2 changes: 1 addition & 1 deletion data_structures/stacks/infix_to_postfix_conversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from __future__ import absolute_import
import string

from .Stack import Stack
from stack import Stack

__author__ = 'Omkar Pathak'

Expand Down
117 changes: 94 additions & 23 deletions graphs/dijkstra.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,50 @@
"""pseudo-code"""

"""
DIJKSTRA(graph G, start vertex s,destination vertex d):
// all nodes initially unexplored
let H = min heap data structure, initialized with 0 and s [here 0 indicates the distance from start vertex]
while H is non-empty:
remove the first node and cost of H, call it U and cost
if U is not explored
mark U as explored
if U is d:
return cost // total cost from start to destination vertex
for each edge(U, V): c=cost of edge(u,V) // for V in graph[U]
if V unexplored:
next=cost+c
add next,V to H (at the end)
DIJKSTRA(graph G, start vertex s, destination vertex d):

//all nodes initially unexplored

1 - let H = min heap data structure, initialized with 0 and s [here 0 indicates
the distance from start vertex s]
2 - while H is non-empty:
3 - remove the first node and cost of H, call it U and cost
4 - if U has been previously explored:
5 - go to the while loop, line 2 //Once a node is explored there is no need
to make it again
6 - mark U as explored
7 - if U is d:
8 - return cost // total cost from start to destination vertex
9 - for each edge(U, V): c=cost of edge(U,V) // for V in graph[U]
10 - if V explored:
11 - go to next V in line 9
12 - total_cost = cost + c
13 - add (total_cost,V) to H

You can think at cost as a distance where Dijkstra finds the shortest distance
between vertexes s and v in a graph G. The use of a min heap as H guarantees
that if a vertex has already been explored there will be no other path with
shortest distance, that happens because heapq.heappop will always return the
next vertex with the shortest distance, considering that the heap stores not
only the distance between previous vertex and current vertex but the entire
distance between each vertex that makes up the path from start vertex to target
vertex.
"""

import heapq


def dijkstra(graph, start, end):
"""Return the cost of the shortest path between vertexes start and end.

>>> dijkstra(G, "E", "C")
6
>>> dijkstra(G2, "E", "F")
3
>>> dijkstra(G3, "E", "F")
3
"""

heap = [(0, start)] # cost from start node,end node
visited = set()
while heap:
Expand All @@ -28,20 +54,65 @@ def dijkstra(graph, start, end):
visited.add(u)
if u == end:
return cost
for v, c in G[u]:
for v, c in graph[u]:
if v in visited:
continue
next = cost + c
heapq.heappush(heap, (next, v))
return (-1, -1)
return -1


G = {
"A": [["B", 2], ["C", 5]],
"B": [["A", 2], ["D", 3], ["E", 1], ["F", 1]],
"C": [["A", 5], ["F", 3]],
"D": [["B", 3]],
"E": [["B", 4], ["F", 3]],
"F": [["C", 3], ["E", 3]],
}

"""
Layout of G2:

E -- 1 --> B -- 1 --> C -- 1 --> D -- 1 --> F
\ /\
\ ||
----------------- 3 --------------------
"""
G2 = {
"B": [["C", 1]],
"C": [["D", 1]],
"D": [["F", 1]],
"E": [["B", 1], ["F", 3]],
"F": [],
}

"""
Layout of G3:

E -- 1 --> B -- 1 --> C -- 1 --> D -- 1 --> F
\ /\
\ ||
-------- 2 ---------> G ------- 1 ------
"""
G3 = {
"B": [["C", 1]],
"C": [["D", 1]],
"D": [["F", 1]],
"E": [["B", 1], ["G", 2]],
"F": [],
"G": [["F", 1]],
}

shortDistance = dijkstra(G, "E", "C")
print(shortDistance) # E -- 3 --> F -- 3 --> C == 6

shortDistance = dijkstra(G2, "E", "F")
print(shortDistance) # E -- 3 --> F == 3

G = {'A': [['B', 2], ['C', 5]],
'B': [['A', 2], ['D', 3], ['E', 1]],
'C': [['A', 5], ['F', 3]],
'D': [['B', 3]],
'E': [['B', 1], ['F', 3]],
'F': [['C', 3], ['E', 3]]}
shortDistance = dijkstra(G3, "E", "F")
print(shortDistance) # E -- 2 --> G -- 1 --> F == 3

shortDistance = dijkstra(G, 'E', 'C')
print(shortDistance)
if __name__ == "__main__":
import doctest
doctest.testmod()
Empty file.
31 changes: 26 additions & 5 deletions project_euler/problem_01/sol1.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,34 @@
'''
"""
Problem Statement:
If we list all the natural numbers below 10 that are multiples of 3 or 5,
we get 3,5,6 and 9. The sum of these multiples is 23.
Find the sum of all the multiples of 3 or 5 below N.
'''
"""
from __future__ import print_function

try:
raw_input # Python 2
raw_input # Python 2
except NameError:
raw_input = input # Python 3
n = int(raw_input().strip())
print(sum([e for e in range(3, n) if e % 3 == 0 or e % 5 == 0]))


def solution(n):
"""Returns the sum of all the multiples of 3 or 5 below n.

>>> solution(3)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please consider adding solution(-7) just to be sure.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will make it tomorrow.

0
>>> solution(4)
3
>>> solution(10)
23
>>> solution(600)
83700
>>> solution(-7)
0
"""

return sum([e for e in range(3, n) if e % 3 == 0 or e % 5 == 0])


if __name__ == "__main__":
print(solution(int(raw_input().strip())))
43 changes: 31 additions & 12 deletions project_euler/problem_01/sol2.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,39 @@
'''
"""
Problem Statement:
If we list all the natural numbers below 10 that are multiples of 3 or 5,
we get 3,5,6 and 9. The sum of these multiples is 23.
Find the sum of all the multiples of 3 or 5 below N.
'''
"""
from __future__ import print_function

try:
raw_input # Python 2
raw_input # Python 2
except NameError:
raw_input = input # Python 3
n = int(raw_input().strip())
sum = 0
terms = (n-1)//3
sum+= ((terms)*(6+(terms-1)*3))//2 #sum of an A.P.
terms = (n-1)//5
sum+= ((terms)*(10+(terms-1)*5))//2
terms = (n-1)//15
sum-= ((terms)*(30+(terms-1)*15))//2
print(sum)


def solution(n):
"""Returns the sum of all the multiples of 3 or 5 below n.

>>> solution(3)
0
>>> solution(4)
3
>>> solution(10)
23
>>> solution(600)
83700
"""

sum = 0
terms = (n - 1) // 3
sum += ((terms) * (6 + (terms - 1) * 3)) // 2 # sum of an A.P.
terms = (n - 1) // 5
sum += ((terms) * (10 + (terms - 1) * 5)) // 2
terms = (n - 1) // 15
sum -= ((terms) * (30 + (terms - 1) * 15)) // 2
return sum


if __name__ == "__main__":
print(solution(int(raw_input().strip())))
98 changes: 57 additions & 41 deletions project_euler/problem_01/sol3.py
Original file line number Diff line number Diff line change
@@ -1,50 +1,66 @@
from __future__ import print_function

'''
"""
Problem Statement:
If we list all the natural numbers below 10 that are multiples of 3 or 5,
we get 3,5,6 and 9. The sum of these multiples is 23.
Find the sum of all the multiples of 3 or 5 below N.
'''
'''
This solution is based on the pattern that the successive numbers in the series follow: 0+3,+2,+1,+3,+1,+2,+3.
'''
"""
from __future__ import print_function

try:
raw_input # Python 2
raw_input # Python 2
except NameError:
raw_input = input # Python 3
n = int(raw_input().strip())
sum=0
num=0
while(1):
num+=3
if(num>=n):
break
sum+=num
num+=2
if(num>=n):
break
sum+=num
num+=1
if(num>=n):
break
sum+=num
num+=3
if(num>=n):
break
sum+=num
num+=1
if(num>=n):
break
sum+=num
num+=2
if(num>=n):
break
sum+=num
num+=3
if(num>=n):
break
sum+=num

print(sum);

def solution(n):
"""
This solution is based on the pattern that the successive numbers in the
series follow: 0+3,+2,+1,+3,+1,+2,+3.
Returns the sum of all the multiples of 3 or 5 below n.

>>> solution(3)
0
>>> solution(4)
3
>>> solution(10)
23
>>> solution(600)
83700
"""

sum = 0
num = 0
while 1:
num += 3
if num >= n:
break
sum += num
num += 2
if num >= n:
break
sum += num
num += 1
if num >= n:
break
sum += num
num += 3
if num >= n:
break
sum += num
num += 1
if num >= n:
break
sum += num
num += 2
if num >= n:
break
sum += num
num += 3
if num >= n:
break
sum += num
return sum


if __name__ == "__main__":
print(solution(int(raw_input().strip())))
Loading