Related
Given an array of n numbers find all the ways of inserting + and - between them so that the result of the expression is positive.
I've found this problem recently and I thought it was interesting, but I'm not exactly sure how to solve it. I think I should try backtracking, no?
Any help or hints are deeply appreciated!
Edit: Would this be a correct solution? (I wrote it in python)
def outputSolution(list):
print(list)
def solution(x, dim):
return len(x) == dim-1
def consistent(list, array):
partial_sum = array[0]
for i in range(len(list)):
if list[i] == 0:
partial_sum = partial_sum - array[i+1]
if list[i] == 1:
partial_sum = partial_sum + array[i+1]
absolute_remaining_sum = 0
for i in range(len(list)+1, len(array)): #the remaining elements in array
absolute_remaining_sum =absolute_remaining_sum + abs(array[i])
if partial_sum + absolute_remaining_sum < 0:
return False
else:
return True
def solve(list, array):
"""
array - the array of n given integers
list - the candidate to a solution
"""
dim = len(array)
for el in range(2): # el = 0 or 1 (0 for - and 1 for +)
if len(list) < dim - 1:
list.append(el)
if consistent(list, array):
if solution(list, dim):
outputSolution(list)
solve(list[:], array)
list.pop()
solve([], array)
My thought process was that there are n-1 gaps between those numbers. Each gap can have a '+' or a '-' in it. And so I build a list where list[i] is equal with 0 if between array[i] and array[i+1] there is an "-", and list[i] is equal with 0 if between array[i] and array[i+1] there is an "+". And I generated all the possible ways of choosing the values in the list, then I checked if that possible candidate is consistent or not. And I said that if the partial sum (calculated using the + and - in our current list) added to the maximum sum of the remaining elements of the given array is a negative number, then the candidate is inconsistent. If the candidate is consistent and it has the required length, then I said that it is a solution.
For example, if I had the array "array = [1,2,3,4,5,6,7]" as input, I was given the following solutions:
[0, 0, 0, 1, 1, 1]
[0, 0, 1, 0, 1, 1]
[0, 0, 1, 1, 0, 1]
[0, 0, 1, 1, 1, 0]
[0, 0, 1, 1, 1, 1]
[0, 1, 0, 0, 1, 1]
[0, 1, 0, 1, 0, 1]
[0, 1, 0, 1, 1, 0]
[0, 1, 0, 1, 1, 1]
[0, 1, 1, 0, 0, 1]
[0, 1, 1, 0, 1, 0]
[0, 1, 1, 0, 1, 1]
[0, 1, 1, 1, 0, 1]
[0, 1, 1, 1, 1, 0]
[0, 1, 1, 1, 1, 1]
[1, 0, 0, 0, 1, 1]
[1, 0, 0, 1, 0, 1]
[1, 0, 0, 1, 1, 0]
[1, 0, 0, 1, 1, 1]
[1, 0, 1, 0, 0, 1]
[1, 0, 1, 0, 1, 1]
[1, 0, 1, 1, 0, 1]
[1, 0, 1, 1, 1, 0]
[1, 0, 1, 1, 1, 1]
[1, 1, 0, 0, 1, 1]
[1, 1, 0, 1, 0, 1]
[1, 1, 0, 1, 1, 0]
[1, 1, 0, 1, 1, 1]
[1, 1, 1, 0, 0, 1]
[1, 1, 1, 0, 1, 0]
[1, 1, 1, 0, 1, 1]
[1, 1, 1, 1, 0, 0]
[1, 1, 1, 1, 0, 1]
[1, 1, 1, 1, 1, 0]
[1, 1, 1, 1, 1, 1]
Backtracking is indeed a reasonable strategy. Since you need to enumerate, there's only one pruning trick that makes an asymptotic difference. Suppose that the array starts with a very large negative number, e.g.,
−50 10 10 10 10 1 2 3 4 5
The sum always includes a −50 term, so the sign for each 10 must be positive since otherwise the remaining numbers aren't large enough to make the overall sum positive. By making the example bigger (more and bigger numbers), we can create an exponential gap between the complexity of naive backtracking and the number of solutions.
If we implement the usual depth-first backtracking strategy and maintain the sum of the absolute values of the remaining array elements, then we can prune every node where the partial sum plus the sum of absolute values is not positive. Since every node not pruned yields at least one solution, we end up with an optimal output-sensitive time complexity.
I'm wondering is there a way I can generate a list whose sublists are all the possible combinations of 0 and 1 with 4 elements? To generate an individual sublist, I have
import random
binum = np.random.randint(2, size=4).tolist()
But how can I get a full list to contain all the possible sublists, each appears once? So the desired output looks like:
[[0,0,0,0],[0,0,0,1]...[1,0,0,1]...[1,1,1,1]]
(There're 16 elements in total for this case). Thanks:)
You basically want all the binary numbers from 0 to 2**n. So, you could use the following code to generate them:
def get_binary_numbers(n):
format_str = f"0{n}b"
max_binary_number = 2**n
return [list(format(i, format_str)) for i in range(max_binary_number)]
Be careful with its performance, if you need big values of n then maybe use the same idea with other ways to generate the lists.
Just iterate over numbers from 0 to 15 and get their binary representation:
In [1]: N = 4
In [2]: def getbit(value, bitnum):
...: mask = 1 << bitnum
...: return (value & mask) >> bitnum
...:
In [3]: [[getbit(i, j) for j in range(N)] for i in range(2 ** N)]
Out[3]:
[[0, 0, 0, 0],
[1, 0, 0, 0],
[0, 1, 0, 0],
[1, 1, 0, 0],
[0, 0, 1, 0],
[1, 0, 1, 0],
[0, 1, 1, 0],
[1, 1, 1, 0],
[0, 0, 0, 1],
[1, 0, 0, 1],
[0, 1, 0, 1],
[1, 1, 0, 1],
[0, 0, 1, 1],
[1, 0, 1, 1],
[0, 1, 1, 1],
[1, 1, 1, 1]]
Same in numpy:
np.unpackbits(np.expand_dims(np.arange(2 ** N, dtype=np.uint8), -1),
axis=1, bitorder='little', count=N)
Also, you can generate the next element by implementing increment operation on binary array:
def gen(l=4):
a = [0 for _ in range(l)]
while True:
yield a.copy()
i = 0
while i < l and a[i]:
a[i] = 0
i += 1
if i == l:
break
a[i] = 1
You can get the cartesian product of your input using itertools library
from itertools import product
bit_sets = product(range(2), repeat=4)
# format your data code ...
more details at https://docs.python.org/3.1/library/itertools.html?highlight=combinations#itertools.product
This just needs the actual necessary parameters from #yesk13's answer, really, using the cartesian product from itertools
for p in it.product([0, 1], repeat=4):
print(p)
(0, 0, 0, 0)
(0, 0, 0, 1)
(0, 0, 1, 0)
(0, 0, 1, 1)
(0, 1, 0, 0)
(0, 1, 0, 1)
(0, 1, 1, 0)
(0, 1, 1, 1)
(1, 0, 0, 0)
(1, 0, 0, 1)
(1, 0, 1, 0)
(1, 0, 1, 1)
(1, 1, 0, 0)
(1, 1, 0, 1)
(1, 1, 1, 0)
(1, 1, 1, 1)
I am looking for an algorithm to iterate over all arrays of length n whose entries are integers between 0 and d and whose sum is k*d. It would be even better if there is a way to do this with built-in Julia functions and iterators. The algorithm should be non-recursive and memory efficient as I am hoping to use this for reasonable values of n.
For small values of n, d, and k, I've written down all such arrays in lexicographical ordering, but I haven't been able to come up with code for iterating through all such arrays.
I think this should work but it requires Combinatorics.jl and ResumableFunctions.jl
using Combinatorics, ResumableFunctions
#resumable function gen_all(n, k, d)
for x in partitions(k*d + n, n)
x = x .- 1
if all(x .<= d)
ys = Set(permutations(x))
for y in ys
#yield y
end
end
end
end
for ga in gen_all(5, 2, 2)
println(ga)
end
gives
[2, 0, 0, 2, 0]
[2, 0, 0, 0, 2]
[0, 0, 2, 2, 0]
[0, 2, 2, 0, 0]
[2, 0, 2, 0, 0]
[0, 2, 0, 2, 0]
[2, 2, 0, 0, 0]
[0, 0, 0, 2, 2]
[0, 0, 2, 0, 2]
[0, 2, 0, 0, 2]
[0, 2, 0, 1, 1]
[0, 1, 1, 0, 2]
[0, 1, 2, 0, 1]
[0, 1, 1, 2, 0]
[2, 1, 1, 0, 0]
[2, 1, 0, 0, 1]
[0, 0, 1, 1, 2]
[1, 2, 1, 0, 0]
[1, 2, 0, 0, 1]
[0, 1, 2, 1, 0]
[0, 1, 0, 1, 2]
[1, 0, 0, 1, 2]
[0, 2, 1, 1, 0]
[2, 0, 0, 1, 1]
[1, 0, 2, 0, 1]
[1, 2, 0, 1, 0]
[0, 1, 0, 2, 1]
[2, 0, 1, 0, 1]
[0, 2, 1, 0, 1]
[1, 0, 1, 2, 0]
[0, 0, 1, 2, 1]
[1, 0, 0, 2, 1]
[2, 1, 0, 1, 0]
[1, 1, 0, 0, 2]
[1, 0, 2, 1, 0]
[1, 0, 1, 0, 2]
[1, 1, 0, 2, 0]
[0, 0, 2, 1, 1]
[2, 0, 1, 1, 0]
[1, 1, 2, 0, 0]
[1, 1, 1, 0, 1]
[1, 1, 0, 1, 1]
[1, 0, 1, 1, 1]
[1, 1, 1, 1, 0]
[0, 1, 1, 1, 1]
I have a matrix like this:
0 1 0 0 1 0
1 0 1 0 1 0
0 1 0 1 0 0
0 0 1 0 1 1
1 1 0 1 0 0
0 0 0 1 0 0
How can I define a matrix in Ruby, and then search through it?
I would like to write a program which searches through all rows and returns rows with the highest sum of "1".
Quick way to define a matrix in Ruby:
Array.new 6, Array.new(6, 0)
# => [
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0]
]
The above code initializes an array with 6 items and defaults their values to the 2nd argument which is another array with 6 items and default values of 0.
In other more imperative languages you would use nested loops:
matrix = []
for x in [0,1,2,3,4,5]
for y in [0,1,2,3,4,5]
matrix[x] ||= [] # create the row as an empty array
matrix[x] << y # push the y value to it
end
end
# matrix is now:
# => [
[0, 1, 2, 3, 4, 5],
[0, 1, 2, 3, 4, 5],
[0, 1, 2, 3, 4, 5],
[0, 1, 2, 3, 4, 5],
[0, 1, 2, 3, 4, 5],
[0, 1, 2, 3, 4, 5]
]
To search through the matrix and find the row with greatest sum:
greatest_sum_row_index = 0
greatest_sum = 0
matrix.each_with_index do |row, i|
# row.inject(:+) is a shortcut to adding each int in the array and returning the sum
sum = row.inject(:+)
if sum > greatest_sum
greatest_sum = sum
greatest_sum_row_index = i
end
end
# highest_row is now the index of the greatest sum row
matrix[greatest_sum_row_index] # returns the row with the greatest sum
If the array were large and memory requirements were a concern, you might do something like this:
def rows_with_most_ones(arr)
arr.each_with_index.with_object([-1, nil]) do |(row,i),best|
tot = row.count(1)
case tot<=>best.first
when 1 then best.replace([tot, [i]])
when 0 then best.last << i
end
end
end
arr = [[0, 1, 0, 0, 1, 0],
[1, 0, 1, 0, 1, 0],
[0, 1, 0, 1, 0, 0],
[0, 0, 1, 0, 1, 1],
[1, 1, 0, 1, 0, 0],
[0, 0, 0, 1, 0, 0]]
rows_with_most_ones(arr)
#=> [3, [1, 3, 4]]
I am trying to edit an algorithm found here.
I want the adjacency matrix to be loaded from file (formatting of the file doesn't matter to me, it can be either like this [0,1,1,0] or just 0110) with G = file.read().split("\n")
However, I get an error no implicit conversion of Fixnum into String (TypeError)
And I already know I need to convert this string to ints, but how to do it properly to not lose the formatting required by this DFS method?
I guess it's pretty easy, but I'm a begginer in Ruby (and graphs :v) and can't get it to work...
Edit:
So the code I'm using to read from file to an array of arrays is:
def read_array(file_path)
File.foreach(file_path).with_object([]) do |line, result|
result << line.split.map(&:to_i)
end
end
And the result I get from a file (for example)
01101010
01010101
01010110
10101011
01011111
is this:
=> [[[1101010], [1010101], [1010110], [10101011], [1011111]]]
What I need, however, is:
=> [[[1,1,0,1,0,1,0], [1,0,1,0,1,0,1], [1,0,1,0,1,1,0], [1,0,1,0,1,0,1,1], [1,0,1,1,1,1,1]]]
So that it would work with the algorithm mentioned in the first line of my post (I'll copy it here, if it takes too much place I can delete it and leave link only):
G = [0,1,1,0,0,1,1], # A
[1,0,0,0,0,0,0],
[1,0,0,0,0,0,0],
[0,0,0,0,1,1,0],
[0,0,0,1,0,1,1],
[1,0,0,1,1,0,0],
[1,0,0,0,1,0,0] # G
LABLES = %w(A B C D E F G)
def dfs(vertex)
print "#{LABLES[vertex]} " # visited
edge = 0
while edge < G.size
G[vertex][edge] = 0
edge += 1
end
edge = 0
while edge < G.size
if ( G[edge][vertex] != 0 && edge != vertex)
dfs(edge)
end
edge += 1
end
end
dfs(0)
split's default separator is a whitespace. To make it split every char you need to explicitly say it:
'01101101'.split.map(&:to_i)
# => [ 1101101 ]
'01101101'.split('').map(&:to_i)
# => [ 0, 1, 1, 0, 1, 1, 0, 1 ]
you can also use chars to do the same job:
'01101101'.chars.map(&:to_i)
# => [ 0, 1, 1, 0, 1, 1, 0, 1 ]
I don't know how your read_array is used, but it can be simplified to:
def read_array(file_path)
File.foreach(file_path).map do |line|
line.chomp.chars.map(&:to_i)
end
end
read_array('my_file.txt')
# => [[1, 1, 0, 1, 0, 1, 0], [1, 0, 1, 0, 1, 0, 1], [1, 0, 1, 0, 1, 1, 0], [1, 0, 1, 0, 1, 0, 1, 1], [1, 0, 1, 1, 1, 1, 1]]
If you still get the extra [, you can either take only the first item:
my_array[0]
Or (if there is more than one item the uber-array) - use flat_map:
uber_array = [[[1, 0, 1, 0, 1, 0, 1], [1, 0, 1, 0, 1, 1, 0], [1, 0, 1, 0, 1, 0, 1, 1]],
[[1, 0, 1, 0, 1, 0, 1, 1], [1, 0, 1, 1, 1, 1, 1]]]
uber_array.flat_map { |a| a }
# => [[1, 0, 1, 0, 1, 0, 1], [1, 0, 1, 0, 1, 1, 0], [1, 0, 1, 0, 1, 0, 1, 1], [1, 0, 1, 0, 1, 0, 1, 1], [1, 0, 1, 1, 1, 1, 1]]