Not a technical question, just asking for a point in the right direction for my research.
Are there any models that address the following problem:
Finding the route starting from X that passes through A, B, C in the most efficient order. In the case below, X,A,C,B is the optimum path (12).
Thanks
you may want to look at traveling salesman. There are a lot of resources for how to implement this as it is a very common programming problem.
https://en.wikipedia.org/wiki/Travelling_salesman_problem
This is an implementation of Dijkstra's Algorithm in Python:
def find_all_paths(graph, start, end, path=[]):
required=('A', 'B', 'C')
path = path + [start]
if start == end:
return [path]
if start not in graph:
return []
paths = []
for node in graph[start]:
if node not in path:
newpaths = find_all_paths(graph, node, end, path)
for newpath in newpaths:
if all(e in newpath for e in required):
paths.append(newpath)
return paths
def min_path(graph, start, end):
paths=find_all_paths(graph,start,end)
mt=10**99
mpath=[]
print '\tAll paths:',paths
for path in paths:
t=sum(graph[i][j] for i,j in zip(path,path[1::]))
print '\t\tevaluating:',path, t
if t<mt:
mt=t
mpath=path
e1=' '.join('{}->{}:{}'.format(i,j,graph[i][j]) for i,j in zip(mpath,mpath[1::]))
e2=str(sum(graph[i][j] for i,j in zip(mpath,mpath[1::])))
print 'Best path: '+e1+' Total: '+e2+'\n'
if __name__ == "__main__":
graph = {'X': {'A':5, 'B':8, 'C':10},
'A': {'C':3, 'B':5},
'C': {'A':3, 'B':4},
'B': {'A':5, 'C':4}}
min_path(graph,'X','B')
Prints:
All paths: [['X', 'A', 'C', 'B'], ['X', 'C', 'A', 'B']]
evaluating: ['X', 'A', 'C', 'B'] 12
evaluating: ['X', 'C', 'A', 'B'] 18
Best path: X->A:5 A->C:3 C->B:4 Total: 12
The 'guts' is recursively finding all paths and filtering to only those paths that visit the required nodes ('A', 'B', 'C'). The paths are then summed up to find the minimum path expense.
There are certainly be more efficient approaches but it is hard to be simpler. You asked for a model, so here is a working implementation.
Related
Let's say we have two arrays m and n containing the characters from the set a, b, c , d, e. Assume each character in the set has a cost associated with it, consider the costs to be a=1, b=3, c=4, d=5, e=7.
for example
m = ['a', 'b', 'c', 'd', 'd', 'e', 'a']
n = ['b', 'b', 'b', 'a', 'c', 'e', 'd']
Suppose we would like to merge m and n to form a larger array s.
An example of s array could be
s = ['a', 'b', 'c', 'd', 'd', 'e', 'a', 'b', 'b', 'b', 'a', 'c', 'e', 'd']
or
s = ['b', 'a', 'd', 'd', 'd', 'b', 'e', 'c', 'b', 'a', 'b', 'a', 'c', 'e']
If there are two or more identical characters adjacent to eachother a penalty is applied which is equal to: number of adjacent characters of the same type * the cost for that character. Consider the second example for s above which contains a sub-array ['d', 'd', 'd']. In this case a penalty of 3*5 will be applied because the cost associated with d is 5 and the number of repetitions of d is 3.
Design a dynamic programming algorithm which minimises the cost associated with s.
Does anyone have any resources, papers, or algorithms they could share to help point me in the right direction?
I have a dictionary with keys representing nodes and values representing possible nodes that the key can traverse to.
Example:
dependecyDict = { 'A': ['D'], 'B': ['A', 'E'], 'C': ['B'], 'D': ['C'], 'G':['H']}
I want to create a new dicitonary, ChainsDict, that will contain all 'values' that each 'key' can traverse to by means of dependecyDict.
For example, the output of the program with this example will be:
ChainsDict = {'A': ['D', 'C', 'B','E'], 'B':['A','D','C','E'], 'C':['B','A','D','E'], 'D':['C','B','A','E'], 'G': ['H']}
I think using a recursive algorithm is the best way to go about making a solution and I tried modifying a shortest path traversing algorithm as follows:
def helper(dependencyDict, ChainsDict):path = []
for key in dependencyDict:
path = path + [(recursiveRowGen(dependencyDict,key))]
for paths in path:
ChainsDict[paths[0]] = paths[1:]
print(finalLineDict)
def recursiveRowGen(dependencyDict,key,path = []):
path = path + [key]
if not key in dependencyDict:
print("no key: ",key)
return path
print(dependencyDict[key])
for blocking in dependencyDict[key]:
if blocking not in path:
newpath = recursiveRowGen(dependencyDict,blocking,path)
if newpath:
return newpath
return path
This code however is having problems capturing the correct output when a key in dependecyDict has more than one value.
I found a hacky solution but it doesn't feel very elegant. Any help is appreciated, thanks!
Here is a recursive solution:
Code
def get_chain_d(argDict):
def each_path(i,caller_chain):
a=[]
caller_chain.append(i)
b = argDict.get(i,[])
for j in b:
if j not in caller_chain:
a.append(j)
a.extend(each_path(j,caller_chain))
return a
return {i:each_path(i,[]) for i in argDict}
dependecyDict = { 'A': ['D'], 'B': ['A', 'E'], 'C': ['B'], 'D': ['C'], 'G':['H']}
print(get_chain_d(dependecyDict))
Output:
{'B': ['A', 'D', 'C', 'E'], 'A': ['D', 'C', 'B', 'E'], 'D': ['C', 'B', 'A', 'E'], 'C': ['B', 'A', 'D', 'E'], 'G': ['H']}
This is basically a graph traversal problem. You can represent each of your key as a node in a graph and its values are the nodes it is connected to.
You can do either Depth-first-search or breadth-first-search for graph. Of course, there's also an iterative and a recursive solution for each of these method. Here's an iterative implementation (I added a few conditionals to eliminate loops):
dependencyDict = { 'A': ['D'], 'B': ['A', 'E'], 'C': ['B'], 'D': ['C'], 'G':['H'] }
chainsDict = {}
for key in dependencyDict:
currKey = key
frontier = [key]
visited = []
while frontier:
currKey = frontier[0]
frontier.remove(currKey)
if dependencyDict.get(currKey,0) and (currKey not in visited) and (currKey not in frontier):
nodes = dependencyDict[currKey]
frontier.extend(nodes)
visited.append(currKey)
elif currKey in visited:
visited.remove(currKey)
elif dependencyDict.get(currKey,0) == 0:
visited.append(currKey)
for i in visited:
if i == key:
visited.remove(i)
chainsDict[key] = visited
print chainsDict
The result looks like:
{'A': ['D', 'C', 'B', 'E'], 'C': ['B', 'A', 'E', 'D'], 'B': ['A', 'E', 'D', 'C'], 'D': ['C', 'B', 'A', 'E'], 'G': ['H']}
G = (V,E) - a directed weighted graph.
D -> G (w:4)
D -> C (w:2)
D -> E (w:2)
C -> F (w:5)
C -> A (w:4)
B -> D (w:3)
B -> E (w:10)
G -> F (w:1)
E -> G (w:6)
A -> D (w:1)
A -> B (w:2)
picture
I use DFS to find all simple path between START=A node to END=F node:
def find_all_paths(self, start, end, path=[]):
path = path + [start]
if start == end:
return [path]
if start not in self.edges:
return []
paths = []
for node in self.edges[start]:
if node not in path:
paths.extend(self.find_all_paths(node, end, path))
return paths
Result:
['A', 'D', 'G', 'F']
['A', 'D', 'C', 'F']
['A', 'D', 'E', 'G', 'F']
['A', 'B', 'D', 'G', 'F']
['A', 'B', 'D', 'C', 'F']
['A', 'B', 'D', 'E', 'G', 'F']
['A', 'B', 'E', 'G', 'F']
I need to get result like this:
['A', 'D', 'G', 'F'], TOTAL_WEIGHT_OF_PATH = 6
['A', 'D', 'C', 'F'], TOTAL_WEIGHT_OF_PATH = 8
['A', 'D', 'E', 'G', 'F'], TOTAL_WEIGHT_OF_PATH = 10
....
....
Where TOTAL_WEIGHT_OF_PATH is sum of weights for each edge in path.
Of course I could just count the TOTAL_WEIGHT_OF_PATH value after getting result of DFS, but I need to calculate it into DFS steps for cutoff searching in condition based on TOTAL_WEIGHT_OF_PATH (e.g. TOTAL_WEIGHT_OF_PATH should be < MAX_WEIGHT_OF_PATH)
Well, notice that the TOTAL_WEIGT_OF_PATH (TWOP) to any node V (other then the root) is TWOP to the preceding node U plus the weight of the edge (U,V). TWOP to root is 0.
TWOP<sub>V</sub> = TWOP<sub>U</sub> + weight(U,V)
Any time you are expanding a new node on a path, you just need to store the TWOP to this node into it, so you don't need to calculate it every time.
Note, that if you visit a node again, using different path, you need to "calculate" a new weight.
I need to generate permutations of with ordering restrictions on ordering
for example, in the list [A,B,C,D]
A must always come before B, and C must always come before D. There also may or may not be E,F,G... that has no restrictions.
The input would look like this: [[A,B],[C,D],[E],[F]]
Is there a way to do this without computing unnecessary permutations or backtracking?
Normally, a permutations algorithm might look somewhat like this (Python):
def permutations(elements):
if elements:
for i, current in enumerate(elements):
front, back = elements[:i], elements[i+1:]
for perm in permutations(front + back):
yield [current] + perm
else:
yield []
You iterate the list, taking each of the elements as the first element, and combining them with all the permutations of the remaining elements. You can easily modify this so that the elements are actually lists of elements, and instead of just using the current element, you pop the first element off that list and insert the rest back into the recursive call:
def ordered_permutations(elements):
if elements:
for i, current in enumerate(elements):
front, back = elements[:i], elements[i+1:]
first, rest = current[0], current[1:]
for perm in ordered_permutations(front + ([rest] if rest else []) + back):
yield [first] + perm
else:
yield []
Results for ordered_permutations([['A', 'B'], ['C', 'D'], ['E'], ['F']]):
['A', 'B', 'C', 'D', 'E', 'F']
['A', 'B', 'C', 'D', 'F', 'E']
['A', 'B', 'C', 'E', 'D', 'F']
[ ... some 173 more ... ]
['F', 'E', 'A', 'C', 'D', 'B']
['F', 'E', 'C', 'A', 'B', 'D']
['F', 'E', 'C', 'A', 'D', 'B']
['F', 'E', 'C', 'D', 'A', 'B']
Note, though, that this will create a lot of intermediate lists in each recursive call. Instead, you could use stacks, popping the first element off the stack and putting it back on after the recursive calls.
def ordered_permutations_stack(elements):
if any(elements):
for current in elements:
if current:
first = current.pop()
for perm in ordered_permutations_stack(elements):
yield [first] + perm
current.append(first)
else:
yield []
The code might be a bit easier to grasp, too. In this case, you have to reserve the sublists, i.e. call it as ordered_permutations_stack([['B', 'A'], ['D', 'C'], ['E'], ['F']])
This question already has answers here:
Generate all strings under length N in C
(2 answers)
Closed 8 years ago.
I m looking for an algorithm that give all possible combinations of letters
Let me explain better. If i have
base-letters = ["a","b","c"];
depth = 2; //max chars allowed
then the expected result would be these 12 elements (3^1 + 3^2 = 12):
["a", "b", "c", "aa","ab","ac","ba","bb","bc","ca", "cb", "cc"]
If i had a depth value = 3, i would expect (3^1) + (3^2) + (3^3) = 39 elements
["a", "b", ... , "aa", "ab", ... , "aaa", "aab", ..., "aba", ...]
Now, if i understood correctly permutation algorithm is similar, but doesn't consider duplicated letters (like "aa","bb","aab", "aba"), and the variable depth value (it could be different then base-letters length).
You can define a recursive function F(s) which takes a string s of length less than or equal to your maximum length, and start by calling F(s) with s equal to the empty string. The function F computes the length of the string and if it is equal to the maximum length, it prints the string s and returns. If the length of the string is less than the maximum, then F(s) prints out the string s and then iterates over all possible letters in the alphabet and for each letter, it adds the letter to the end of string s to produce a string s' of length one more, and then calls F(s'). This has very low memory usage and is essentially the fastest method possible, at least in asymptotic terms.
In Python, use itertools's permutations function (a code recipe is included if you need to translate the code to your native language)
>>> import itertools
>>> base_elements = ['a', 'b', 'cow']
>>> max_depth = 2
>>> result = [''.join(element) for element in itertools.chain.from_iterable([itertools.permutations(base_elements, depth) for depth in range(1, max_depth+1)])]
>>> print(result)
['a', 'b', 'cow', 'ab', 'acow', 'ba', 'bcow', 'cowa', 'cowb']
If you want only unique values, then rather than concatenating the each output element into a string, create a set. This removes duplicates. Then remove duplicates from the final set.
>>> result = frozenset([frozenset(element)
for element in itertools.chain.from_iterable(
[itertools.permutations(base_elements, depth)
for depth in range(1, max_depth+1)]
)])
Or more cleanly,
def permutations(base_elements, max_depth):
result = set()
for depth in range(1, max_depth+1):
for element in itertools.permutations(base_elements, depth):
result.add(frozenset(element))
return result
It seems this code will give you what you need:
def all_strs(iterable, depth):
results = []
if depth==1:
for item in iterable:
results.append(str(item))
return results
for item in iterable:
for s in all_strs(iterable, depth-1):
results.append(str(item) + s)
return results
if __name__ == "__main__":
print all_strs('abc', 2)
print all_strs([1, 2, 3], 3)
s = 'abc'
results = []
for i in range(len(s)):
results += print all_strs(s, i+1)
print results
the output is:
['aa', 'ab', 'ac', 'ba', 'bb', 'bc', 'ca', 'cb', 'cc']
['111', '112', '113', '121', '122', '123', '131', '132', '133', '211', '212', '213', '221', '222', '223', '231', '232', '233', '311', '312', '313', '321', '322', '323', '331', '332', '333']
['a', 'b', 'c', 'aa', 'ab', 'ac', 'ba', 'bb', 'bc', 'ca', 'cb', 'cc', 'aaa', 'aab', 'aac', 'aba', 'abb', 'abc', 'aca', 'acb', 'acc', 'baa', 'bab', 'bac', 'bba', 'bbb', 'bbc', 'bca', 'bcb', 'bcc', 'caa', 'cab', 'cac', 'cba', 'cbb', 'cbc', 'cca', 'ccb', 'ccc']