Sum of integers with restrictrions - recursion

Getting right to the gist of the problem:
In how many ways can we add k positive integers to reach a sum of exactly n if each number is smaller or equal to given number m?
The problem is solvable with dynamic programming but I am stuck because I cannot find the optimal substructure or recursion for the solution.

Here's a simple function in Python 3 that should fit your description. I assume that 0 is not an acceptable value but it's a trivial change if it is.
def howMany(k, n, m):
def sub(pos, currentSum, path):
if currentSum == n and pos == k: # reached the sum, print result and increase counter by 1
print(path)
return 1
elif currentSum < n and pos < k: # still worth trying
count = 0
for i in range(1, m):
count += sub(pos + 1, currentSum + i, path+[i])
return count
else: # abort
return 0
return sub(0, 0, [])
print(howMany(3, 10, 6))
yields
[1, 4, 5]
[1, 5, 4]
[2, 3, 5]
[2, 4, 4]
[2, 5, 3]
[3, 2, 5]
[3, 3, 4]
[3, 4, 3]
[3, 5, 2]
[4, 1, 5]
[4, 2, 4]
[4, 3, 3]
[4, 4, 2]
[4, 5, 1]
[5, 1, 4]
[5, 2, 3]
[5, 3, 2]
[5, 4, 1]
18
It could be optimised but that would obfuscate the logic at this stage.

Related

Is there a basic implementation of bellman ford's algorithm in julia?

I'm a first year student who's learning Julia as a first programming language. I have a project about bellman ford's algorithm but it seems every code is a bit more advanced than I can currently understand. Is there a basic code like Dfs or Bfs for this that a starter could understand, if u have, do share.
This is implemented in LightGraphs
using LightGraphs
g = erdos_renyi(20, 100, seed=1)
bf_state = bellman_ford_shortest_paths(g, 1)
And now we can display all paths found in the graph:
julia> enumerate_paths(bf_state)
20-element Vector{Vector{Int64}}:
[]
[1, 4, 2]
[1, 3]
[1, 4]
[1, 5]
[1, 11, 6]
[1, 7]
[1, 3, 8]
[1, 3, 9]
[1, 7, 10]
[1, 11]
[1, 12]
[1, 3, 13]
[1, 3, 14]
[1, 15]
[1, 4, 16]
[1, 17]
[1, 3, 18]
[1, 19]
[1, 5, 20]

Julia idiomatic way to split vector to subvectors based on condition

Let's say I have a vector a = [1, 0, 1, 2, 3, 4, 5, 0, 5, 6, 7, 8, 0, 9, 0] and I want to split it to smaller vectors based on a condition depending on value in that array. E.g. value being zero.
Thus I want to obtain vector of following vectors
[1, 0]
[1, 2, 3, 4, 5, 0]
[5, 6, 7, 8, 0]
[9, 0]
So far this was working for me as a naive solution, but it loses the type.
function split_by_λ(a::Vector, λ)
b = []
temp = []
for i in a
push!(temp, i)
if λ(i)
push!(b, temp)
temp = []
end
end
b
end
split_by_λ(a, isequal(0))
Then I tried to play with ranges, which feels a bit more idiomatic, and does not lose the type.
function split_by_λ(a::Vector, λ)
idx = findall(λ, a)
ranges = [(:)(i==1 ? 1 : idx[i-1]+1, idx[i]) for i in eachindex(idx)]
map(x->a[x], ranges)
end
split_by_λ(a, isequal(0))
but it still feels very cumbersome regarding it's a rather simple task.
Is there something I'm missing, some easier way?
Maybe someone has a shorter idea but here is mine:
julia> inds = vcat(0,findall(==(0),a),length(a))
julia> getindex.(Ref(a), (:).(inds[1:end-1].+1,inds[2:end]))
5-element Array{Array{Int64,1},1}:
[1, 0]
[1, 2, 3, 4, 5, 0]
[5, 6, 7, 8, 0]
[9, 0]
[]
Or if you want to avoid copying a
julia> view.(Ref(a), (:).(inds[1:end-1].+1,inds[2:end]))
5-element Array{SubArray{Int64,1,Array{Int64,1},Tuple{UnitRange{Int64}},true},1}:
[1, 0]
[1, 2, 3, 4, 5, 0]
[5, 6, 7, 8, 0]
[9, 0]
0-element view(::Array{Int64,1}, 16:15) with eltype Int64
Pretty much the same as Przemyslaw's answer, but maybe less cryptic dense:
function split_by(λ, a::Vector)
first, last = firstindex(a), lastindex(a)
splits = [first-1; findall(λ, a); last]
s1, s2 = #view(splits[1:end-1]), #view(splits[2:end])
return [view(a, i1+1:i2) for (i1, i2) in zip(s1, s2)]
end
Also, I changed the signature to the conventional one of "functions first", which allows you to use do-blocks. Additionally, this should work with offset indexing.
One could surely get rid of the intermediate allocations, but I think that gets ugly without yield:
function split_by(λ, a::Vector)
result = Vector{typeof(view(a, 1:0))}()
l = firstindex(a)
r = firstindex(a)
while r <= lastindex(a)
if λ(a[r])
push!(result, #view(a[l:r]))
l = r + 1
end
r += 1
end
push!(result, #view(a[l:end]))
return result
end

From a list of ints extract all consecutive repetitions in a list of lists

Extract all consecutive repetitions in a given list:
list1 = [1,2,2,3,3,3,3,4,5,5]
It should yield a list like this
[[2,2],[3,3,3,3],[5,5]]
I tried the code below. I know it is not the proper way to solve this problem but I could not manage how to solve this.
list1 = [1,2,2,3,3,3,3,4,5,5]
list2 = []
for i in list1:
a = list1.index(i)
if list1[a] == list1[a+1]:
list2.append([i,i])
print(list2)
You can use this to achieve it. There are "easier" solutions using itertools and groupby to get the same result, this is how to do it "by hand":
def FindInnerLists(l):
'''reads a list of int's and groups them into lists of same int value'''
result = []
allResults = []
for n in l:
if not result or result[0] == n: # not result == empty list
result.append(n)
if result[0] != n: # number changed, so we copy the list over into allResults
allResults.append(result[:])
result = [n] # and add the current to it
# edge case - if result contains elements, add them as last item to allResults
if result:
allResults.append(result[:])
return allResults
myl = [2, 1, 2, 1, 1, 1, 1, 2, 2, 2, 1, 2, 7, 1, 1, 1,2,2,2,2,2]
print(FindInnerLists(myl))
Output (works for 2.6 and 3.x):
[[2], [1], [2], [1, 1, 1, 1], [2, 2, 2], [1], [2], [7], [1, 1, 1], [2, 2, 2, 2, 2]]
Another way to do it:
list1 = [1, 2, 2, 3, 3, 3, 3, 4, 5, 5]
result = [[object()]] # initiate the result with object() as a placeholder
for element in list1: # iterate over the rest...
if result[-1][0] != element: # the last repeated element does not match the current
if len(result[-1]) < 2: # if there was less than 2 repeated elements...
result.pop() # remove the last element
result.append([]) # create a new result entry for future repeats
result[-1].append(element) # add the current element to the end of the results
if len(result[-1]) < 2: # finally, if the last element wasn't repeated...
result.pop() # remove it
print(result) # [[2, 2], [3, 3, 3, 3], [5, 5]]
And you can use it on any kind of a list, not just numerical.
This would work:
list1 = [1,2,2,3,3,3,3,4,5,5]
res = []
add = True
last = [list1[0]]
for elem in list1[1:]:
if last[-1] == elem:
last.append(elem)
if add:
res.append(last)
add = False
else:
add = True
last = [elem]
print(res)
Output:
[[2, 2], [3, 3, 3, 3], [5, 5]]

Find all cycles of given length (networkx)

Given an undirected graph how do you go about finding all cycles of length n (using networkx if possible). So input would be the Graph and n and the function would return all cycles of that length.
You can use networkx.cycle_basis.
>>> G = networkx.Graph()
>>> networkx.add_cycle(G, [0, 1, 2, 3])
>>> networkx.add_cycle(G, [0, 3, 4, 5])
>>> print(networkx.cycle_basis(G))
[[3, 4, 5, 0], [1, 2, 3, 0]]
>>> print(networkx.cycle_basis(G, root = 2))
[[1, 2, 3, 0]]
Then, you can check the length of each list as you see fit.

Sum of column elements of dictionary values made of lists in Python

I have a dictionary as follows
d = {0:[1,2,3], 1:[2,3,4], 2:[3,4,5], 3:[4,5,6]}
What wold be the most compact form in Python to sum the same column elements of the dictionary values which are lists or how can I get the following result out of dictionary values ?
[(1+2+3+4), (2+3+4+5), (3+4+5+6)]=[10,14,18]
Without NumPy
>>> d
{0: [1, 2, 3], 1: [2, 3, 4], 2: [3, 4, 5], 3: [4, 5, 6]}
>>> map(sum, zip(*d.values()))
[10, 14, 18]
with NumPy
>>> import numpy as np
>>> d
{0: [1, 2, 3], 1: [2, 3, 4], 2: [3, 4, 5], 3: [4, 5, 6]}
>>> map(np.sum, zip(*d.values()))
[10, 14, 18]

Resources