Tripartite Matching: Graph Algorithm, Run Time Error - python

I am practicing problems on Graphs on Hacker Rank. Below is the link for the problem
https://www.hackerrank.com/challenges/tripartite-matching
I wrote a piece of code and the code seems to run on the test case that is being given. I created some test cases of my own and manually calculated the output and then ran my program and it works. However, for most of the other test cases on Hacker Rank. I get a Run Time Error. I am not sure which Run Time Error it is.
I think my logic is breaking for large input sizes. But I am not sure how.
Below is my code.
'''
Input Sequence
3
2
1 2
2 3
3
1 2
1 3
2 3
2
1 3
2 3
'''
#Stores the data of the graph
class Graph:
def __init__(self,parent_node,child_node):
self.node_map = {}
self.node_map[parent_node] = [child_node]
self.node_map[child_node] = [parent_node]
def getNodeMap(self):
return self.node_map
def deleteKey(self, parent_node):
del self.node_map[parent_node]
def printGraph(self):
print self.node_map
def getChildren(self, parent_node):
return self.node_map[parent_node]
def getAllParents(self):
return self.node_map.keys()
def add(self,parent_node,child_node):
#Adding the Node and Edge Details
# Adding Parent and Child
if (parent_node in self.node_map):
child_list = []
child_list = self.node_map[parent_node]
child_list.append(child_node)
self.node_map[parent_node] = child_list
else:
self.node_map[parent_node] = [child_node]
if (child_node in self.node_map):
parent_list = self.node_map[child_node]
parent_list.append(parent_node)
self.node_map[child_node] = parent_list
else:
self.node_map[child_node] = [parent_node]
def runDFS(parent,seq,graph_num):
#print seq
if(graph_num == len(all_graphs)):
all_sequences.append(seq)
return
else:
if(parent not in all_graphs[graph_num].getAllParents()):
return
children = all_graphs[graph_num].getChildren(parent)
for child in children:
new_set = copy.deepcopy(s)
new_seq = copy.deepcopy(seq)
new_seq.append(child)
runDFS(child,new_seq,graph_num+1)
import sys
import fileinput
import copy
import sys
all_graphs = []
all_sequences = []
list_sequences = []
graphs = raw_input()
#print 'Graphs are', graphs
g = [Graph for i in range(int(graphs))]
for i in range(0,int(graphs)):
g[i] = Graph(-999*i,-999*i)
#print 'Read no. of Edges'
edges = raw_input()
#print edges
for j in range(0,int(edges)):
#print 'Read Edge Info'
edge_info = raw_input()
parent_node = edge_info[0]
child_node = edge_info[2]
g[i].add(parent_node, child_node)
g[i].deleteKey(-999*i)
all_graphs.append(g[i])
#for i in range(0,len(all_graphs)):
# print all_graphs[i].getNodeMap()
graph_num = 0
all_sequences = []
sys.setrecursionlimit(20000)
for item in all_graphs[graph_num].getAllParents():
s = set()
s.add(item)
seq = list()
seq.append(item)
runDFS(item,seq,graph_num)
#print all_sequences
counter = 0
for item in all_sequences:
#print item
end_node = item[len(item)-1]
start_node = item[0]
if(end_node == start_node):
counter = counter + 1
print counter
Would really appreciate some help. Is there a bug in my logic or is my assumption right?
If the code is not working for larger input sizes than what is the best way to optimize it?
Instead of running DFS, I used the following approach. But the same thing happens here as well. I think there is some problem with my IO. I am not able to figure out what... :(
for itemA in all_graphs[0].getAllParents():
for itemB in all_graphs[0].getChildren(itemA):
for itemC in all_graphs[1].getChildren(itemB):
if(itemA in all_graphs[2].getChildren(itemC)):
counter = counter + 1
print counter

Related

Solving Dijkstra's algorithm - passing costs / parents with two edges

I have a graph like this:
# graph table
graph = {}
graph['start'] = {}
graph['start']['a'] = 5
graph['start']['b'] = 2
graph['a'] = {}
graph['a']['c'] = 4
graph['a']['d'] = 2
graph['b'] = {}
graph['b']['a'] = 8
graph['b']['d'] = 7
graph['c'] = {}
graph['c']['d'] = 6
graph['c']['finish'] = 3
graph['d'] = {}
graph['d']['finish'] = 1
graph['finish'] = {}
And I am trying to find the fastest way from S to F.
In the first example in the book only one edge was connected to one node, in this example for example, node D has 3 weights and a cost table was used:
costs = {}
infinity = float('inf')
costs['a'] = 5
costs['b'] = 2
costs['c'] = 4
costs['d'] = # there is 3 costs to node D, which one to select?
costs['finish'] = infinity
And a parents table:
parents = {}
parents['a'] = 'start' # why not start and b since both `S` and `B` can be `A` nodes parent?
parents['b'] = 'start'
parents['c'] = 'a'
parents['d'] = # node D can have 3 parents
parents['finish'] = None
But this also works, by works I mean no error is thrown, so do I only have to name the parents from the first node S?
parents = {}
parents['a'] = 'start'
parents['b'] = 'start'
parents['finish'] = None
The code:
processed = []
def find_lowest_cost_node(costs):
lowest_cost = float('inf')
lowest_cost_node = None
for node in costs:
cost = costs[node]
if cost < lowest_cost and node not in processed:
lowest_cost = cost
lowest_cost_node = node
return lowest_cost_node
node = find_lowest_cost_node(costs)
while node is not None:
cost = costs[node]
neighbors = graph[node]
for n in neighbors.keys():
new_cost = cost + neighbors[n]
if costs[n] > new_cost:
costs[n] = new_cost
parents[n] = node
processed.append(node)
node = find_lowest_cost_node(costs)
def find_path(parents, finish):
path = []
node = finish
while node:
path.insert(0, node)
if parents.__contains__(node):
node = parents[node]
else:
node = None
return path
path = find_path(parents, 'finish')
distance = costs['finish']
print(f'Path is: {path}')
print(f'Distance from start to finish is: {distance}')
I get:
Path is: ['finish']
Distance from start to finish is: inf
Where is my mistake and how should I add cost and parent to a node which can be visited from more than 1 node?
Edit
I do believe this is not the best approach for this problem, the best in practice solution / recommendations are welcome.
You do not need to initialise the cost table with more than costs['start'] = 0 or the parents dictionary with more than parents = {}. That is what your algorithm is going to create for you!
The only other change you need to make is to your while loop. It just needs to check whether the new node has already been detected before. If so then we check to see whether the new path is shorter and update as required; if not then we establish the new path.
while node is not None:
cost = costs[node]
neighbors = graph[node]
for n in neighbors.keys():
new_cost = cost + neighbors[n]
if n in costs:
if costs[n] > new_cost:
costs[n] = new_cost
parents[n] = node
else:
costs[n] = new_cost
parents[n] = node
processed.append(node)
node = find_lowest_cost_node(costs)
I think there are much neater ways to deal with graphs but this is the minimal change needed to make your code work as required. Hope it's helpful!

i need to access a element from the linked list like the one i did on the normal list but cant - python

What im trying to solve is ''Calculate the time to access the element stored in each randomly generated index
for both Python list and linked list. For example, n[5] is 45603. We will be
accessing the 45603. Element in both the Python list and the linked list. We know
that the Python list should immediately access the data, whereas the linked list
would take some time. Print all the accessed values to make sure that everything is
all-right'' this question
b = 0
c = 0
import random
import time
x = 0
N = int(input('Enter the N :'))
n = int(input('Enter the n: '))
data = []
while x<N:
data.append(random.randint(1, N))
x = x + 1
class Node(object):
def __init__(self, value, next=None,position = 0):
self.value = value
self.reference = next
self.position = position
#convert the list to linked
class LinkedList(object):
def __init__(self, sequence):
self.head = Node(sequence[0])
current = self.head
for item in sequence[1:]:
current.reference = Node(item)
current = current.reference
def listprint(self):
printval = self.head
while printval is not None:
print (printval.value)
printval = printval.reference
a = range(10)
datal = LinkedList(data)
current = datal.head
while current is not None:
print(current.value)
current = current.reference
for i in range(n):
randv = random.randint(1,n)
start1 = time.time()
data[randv]
end1 = time.time()
elapsed1 = end1 - start1
print('sample id',b,' ','Random İndex ',randv)
print(data[randv])
print('Access time',elapsed1)
b = b + 1

Getting TypeError balance_pos_phrases() missing 1 required positional argument

The code mentioned below was working fine without the a class called "BigramsClassifier()" but since a class was needed i added it included the reference "self" as required. Then i got this error as seen below. However, this solution posted here worked for a similar issue of mine but not this.
This is the code with the class included,
class BigramsClassifier(object): #line 40
def __init__(self):
pass
def remove_duplicates(self,numbers):
numbers.sort()
i = len(numbers) - 1
while i > 0:
if numbers[i] == numbers[i - 1]:
numbers.pop(i)
i -= 1
return numbers
def balance_pos_phrases(self,pos_list,neg_list):
new_mix = list(set(pos_list).intersection(set(neg_list))) # gets only the common words between two classes
for item in new_mix:
for pos_i in pos_list:
if item in pos_list:
pos_list.remove(item)
pos_list = self.remove_duplicates(pos_list)
return pos_list
def balance_neg_phrases(self,pos_list, neg_list):
new_mix = list(set(neg_list).intersection(set(pos_list))) # gets only the common words between two classes
for item in new_mix:
for neg_i in neg_list:
if item in neg_list:
neg_list.remove(item)
neg_list = self.remove_duplicates(neg_list)
return neg_list
short_pos = open("\positive4.txt", "r").read()
short_neg = open("\\negative4.txt", "r").read()
pos_documents = []
neg_documents = []
all_words = []
allowed_word_types = ["J", "N", "V"] # J-Adjectives, N-nouns, V-Verb, R-Adverb
for p in short_pos.split('\n'):
pos_documents.append((p, "pos"))
words = word_tokenize(p)
pos = nltk.pos_tag(words)
for w in pos:
if w[1][0] in allowed_word_types:
all_words.append(w[0].lower())
for p in short_neg.split('\n'):
neg_documents.append((p, "neg"))
words = word_tokenize(p)
pos = nltk.pos_tag(words)
for w in pos:
if w[1][0] in allowed_word_types:
all_words.append(w[0].lower())
short_pos_words = word_tokenize(short_pos)
short_neg_words = word_tokenize(short_neg)
balanced_pos_words = balance_pos_phrases(short_pos_words, short_neg_words) ####line 104####
balanced_neg_words = balance_neg_phrases(short_pos_words, short_neg_words)

Parsing a tree using python

I have to make a program that parses a tree represented using a set parenthesis and numbers. So each parenthesis represent node in a tree and the program is supposed to print out all the children nodes for each parent node. The python code is as follows:
class context(object):
def __init__(self, label=None, parent=None, children=[]):
self.label = label
self.parent = parent
self.children = []
self.list = []
def make_tree(self, tree):
stack = []
index = 0
while index < len(tree):
if tree[index] is '(':
if self.label is None:
self.label = tree[index+1]
index = index+1
else:
if len(stack) == 0:
stack.append(context(tree[index+1], self.label))
index = index+1
else:
stack.append(context(tree[index+1], stack[len(stack)-1].label))
index = index+1
elif tree[index] is ')':
if len(stack) == 1:
self.children.append(stack.pop())
return
else:
stack[len(stack)-2].children.append(stack.pop())
index = index+1
def traverse(self, size, obj):
if self.label is None or size == 0:
return []
temp_list = []
temp = []
dic = {}
tt = [children.label for children in obj.children]
dic[obj.label] = tt
temp.append(dic)
for child in obj.children:
temp_list = child.traverse(len(child.children), child)
print temp
return temp + temp_list
line = '( Root ( 1 ( 2 ) ( 3 ( 4 ) ( 5 ) ) ( 6 ( 7 ) ( 8 ( 9 ) ) ) ) ) '.split()
test = context()
test.make_tree(line)
final = test.traverse(len(test.children), test)
The result have to be this.
If I print out the list in the make_tree function, I get correct result... But the final result is not correct. In this case, I am missing {'3':['4','5']}
Any comment??
I just looked at some of your code. It didn't have much time so I couldn't have really debugged it way more but you can also implement by having tmpList in the way belong and basically keep updating at every point. Alko's solution works as well, but this might be a bit more clear.
def traverse(self, size, obj, tmpList):
if self.label is None or size == 0:
return []
dic = {}
tt = [children.label for children in obj.children]
dic[obj.label] = tt
tmpList.append(dic)
for child in obj.children:
child.traverse(len(child.children), child, tmpList)
return tmpList
You call this by:
final = test.traverse(len(test.children), test, [])
You overwrite child results with assignment to temp_list, you probably want instead do:
for child in obj.children:
temp_list += child.traverse(len(child.children), child)

Python - Dijsktra's Algorithm Distance Problem

I've run into a problem with my code, i'm not able to calculate the distance to a node from the starting node. I have a text file of the form:
1,2,3,4,5,6,7,8,9
1,2,3,4,5,6,7,8,9
This represents the node distances in the graph. Here is my code, unfortunately, despite trying a few different methods I still keep coming up with various error messages.
infinity = 1000000
invalid_node = -1
startNode = 0
class Node:
distFromSource = infinity
previous = invalid_node
visited = False
def populateNodeTable():
nodeTable = []
index =0
f = open('route.txt', 'r')
for line in f:
node = map(int, line.split(','))
nodeTable.append(Node())
print nodeTable[index].previous
print nodeTable[index].distFromSource
index +=1
nodeTable[startNode].distFromSource = 0
return nodeTable
def tentativeDistance(currentNode, nodeTable):
nearestNeighbour = []
for currentNode in nodeTable:
# if Node[currentNode].distFromSource + currentDistance = startNode + currentNode
# currentDistance = currentNode.distFromSource + nodeTable.currentNode
currentNode.previous = currentNode
currentNode.length = currentDistance
currentNode.visited = True
currentNode +=1
nearestNeighbour.append(currentNode)
print nearestNeighbour
return nearestNeighbour
def shortestPath (nearestNeighbour)
shortestPath = []
f = open ('spf.txt', 'r')
f.close()
currentNode = startNode
if __name__ == "__main__":
populateNodeTable()
tentativeDistance(currentNode,populateNodeTable())
The lines starting with '#' in my tentativeDistance function is the section giving me trouble. I've looked at some other implementations on the web though they confuse me
I have been programming the Dijkstra's Algorithm in Python a few months ago; its tested and it should work:
def dijkstra(u,graph):
n = graph.numNodes
l = { u : 0 } ; W = graph.V()
F = [] ; k = {}
for i in range(0,n):
lv,v = min([ (l[lk],lk) for lk in l.keys() if lk in W ])
W.remove(v)
if v!=u: F.append(k[v])
for v1 in [ v2 for v2 in graph.G(v) if v2 in W ]:
if v1 not in l or l[v]+graph.w(v,v1) < l[v1]:
l[v1] = l[v] + graph.w(v,v1)
k[v1] = (v,v1)
return l,F
You need a class Graph with Method V() (which yields the graphs nodes), w(v1,v2) (which yields the weight of the edge (v1,v2)), remove (which removes an edge from a graph) and attribute numNodes (which yields the number of nodes in the graph) and G(v) which yields the neighborhood of node v.

Categories