I'm having a hard time getting started to layout code for this problem.
I have a fixed amount of random numbers, in this case 8 numbers.
R[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
That are going to be placed in 3 sets of numbers, with the only constraint that each set contain minimum one value, and each value can only be used once. Edit: all 8 numbers should be used
For example:
R1[] = { 1, 4 }
R2[] = { 2, 8, 5, 6 }
R3[] = { 7, 3 }
I need to loop through all possible combinations of a set R1, R2, R3. Order is not important, so if the above example happened, I don't need
R1[] = { 4, 1 }
R2[] = { 2, 8, 5, 6 }
R3[] = { 7, 3 }
NOR
R1[] = { 2, 8, 5, 6 }
R2[] = { 7, 3 }
R3[] = { 1, 4 }
What is a good method?
I have in front of me Knuth Volume 4, Fascicle 3, Generating all Combinations and Partitions, section 7.2.1.5 Generating all set partitions (page 61 in fascicle).
First he details Algorithm H, Restricted growth strings in lexicographic order due to George Hutchinson. It looks simple, but I'm not going to dive into it just now.
On the next page under an elaboration Gray codes for set partitions he ponders:
Suppose, however, that we aren't interested in all of the partitions; we might want only the ones that have m blocks. Can we run this through the smaller collection of restricted growth strings, still changing one digit at a time?
Then he details a solution due to Frank Ruskey.
The simple solution (and certain to be correct) is to code Algorithm H filtering on partitions where m==3 and none of the partitions are the empty set (according to your stated constraints). I suspect Algorithm H runs blazingly fast, so the filtering cost will not be large.
If you're implementing this on an 8051, you might start with the Ruskey algorithm and then only filter on partitions containing the empty set.
If you're implementing this on something smaller than an 8051 and milliseconds matter, you can seed each of the three partitions with a unique element (a simple nested loop of three levels), and then augment by partitioning on the remaining five elements for m==3 using the Ruskey algorithm. You won't have to filter anything, but you do have to keep track of which five elements remain to partition.
The nice thing about filtering down from the general algorithm is that you don't have to verify any cleverness of your own, and you change your mind later about your constraints without having to revise your cleverness.
I might even work a solution later, but that's all for now.
P.S. for the Java guppies: I discovered searching on "George Hutchison restricted growth strings" a certain package ca.ubc.cs.kisynski.bell with documentation for method growthStrings() which implements the Hutchison algorithm.
Appears to be available at http://www.cs.ubc.ca/~kisynski/code/bell/
Probably not the best approach but it should work.
Determine number of combinations of three numbers which sum to 8:
1,1,6
1,2,5
1,3,4
2,2,4
2,3,3
To find the above I started with:
6,1,1 then subtracted 1 from six and added it to the next column...
5,2,1 then subtracted 1 from second column and added to next column...
5,1,2 then started again at first column...
4,2,2 carry again from second to third
4,1,3 again from first...
3,2,3 second -> third
3,1,4
knowing that less than half is 2 all combinations must have been found... but since the list isn't long we might as well go to the end.
Now sort each list of 3 from greatest to least(or vice versa)
Now sort each list of 3 relative to each other.
Copy each unique list into a list of unique lists.
We now have all the combinations which add to 8 (five lists I think).
Now consider a list in the above set
6,1,1 all the possible combinations are found by:
8 pick 6, (since we picked six there is only 2 left to pick from) 2 pick 1, 1 pick 1
which works out to 28*2*1 = 56, it is worth knowing how many possibilities there are so you can test.
n choose r (pick r elements from n total options)
n C r = n! / [(n-r)! r!]
So now you have the total number of iterations for each component of the list for the first one it is 28...
Well picking 6 items from 8 is the same as creating a list of 8 minus 2 elements, but which two elements?
Well if we remove 1,2 that leaves us with 3,4,5,6,7,8. Lets consider all groups of 2... Starting with 1,2 the next would be 1,3... so the following is read column by column.
12
13 23
14 24 34
15 25 35 45
16 26 36 46 56
17 27 37 47 57 67
18 28 38 48 58 68 78
Summing each of the above columns gives us 28. (so this only covered the first digit in the list (6,1,1) repeat the procedure for the second digit (a one) which is "2 Choose 1" So of the left over two digits from the above list we pick one of two and then for the last we pick the remaining one.
I know this is not a detailed algorithm but I hope you'll be able to get started.
Turn the problem on it's head and you'll find a straight-forward solution. You've got 8 numbers that each need to be assigned to exactly one group; The "solution" is only a solution if at least one number got assigned to each group.
The trivial implementation would involve 8 for loops and a few IF's (pseudocode):
for num1 in [1,2,3]
for num2 in [1,2,3]
for num3 in [1,2,3]
...
if ((num1==1) or (num2==1) or (num3 == 1) ... (num8 == 1)) and ((num1 == 2) or ... or (num8 == 2)) and ((num1 == 3) or ... or (num8 == 3))
Print Solution!
It may also be implemented recursively, using two arrays and a couple of functions. Much nicer and easier to debug/follow (pseudocode):
numbers = [1, 2, 3, 4, 5, 6, 7, 8]
positions = [0, 0, 0, 0, 0, 0, 0, 0]
function HandleNumber(i) {
for position in [1,2,3] {
positions[i] = position;
if (i == LastPosition) {
// Check if valid solution (it's valid if we got numbers in all groups)
// and print solution!
}
else HandleNumber(i+1)
}
}
The third implementation would use no recursion and a little bit of backtracking. Pseudocode, again:
numbers = [1,2,3,4,5,6,7,8]
groups = [0,0,0,0,0,0,0,0]
c_pos = 0 // Current position in Numbers array; We're done when we reach -1
while (cpos != -1) {
if (groups[c_pos] == 3) {
// Back-track
groups[c_pos]=0;
c_pos=c_pos-1
}
else {
// Try the next group
groups[c_pos] = groups[c_pos] + 1
// Advance to next position OR print solution
if (c_pos == LastPostion) {
// Check for valid solution (all groups are used) and print solution!
}
else
c_pos = c_pos + 1
}
}
Generate all combinations of subsets recursively in the classic way. When you reach the point where the number of remaining elements equals the number of empty subsets, then restrict yourself to the empty subsets only.
Here's a Python implementation:
def combinations(source, n):
def combinations_helper(source, subsets, p=0, nonempty=0):
if p == len(source):
yield subsets[:]
elif len(source) - p == len(subsets) - nonempty:
empty = [subset for subset in subsets if not subset]
for subset in empty:
subset.append(source[p])
for combination in combinations_helper(source, subsets, p+1, nonempty+1):
yield combination
subset.pop()
else:
for subset in subsets:
newfilled = not subset
subset.append(source[p])
for combination in combinations_helper(source, subsets, p+1, nonempty+newfilled):
yield combination
subset.pop()
assert len(source) >= n, "Not enough items"
subsets = [[] for _ in xrange(n)]
for combination in combinations_helper(source, subsets):
yield combination
And a test:
>>> for combination in combinations(range(1, 5), 2):
... print ', '.join(map(str, combination))
...
[1, 2, 3], [4]
[1, 2, 4], [3]
[1, 2], [3, 4]
[1, 3, 4], [2]
[1, 3], [2, 4]
[1, 4], [2, 3]
[1], [2, 3, 4]
[2, 3, 4], [1]
[2, 3], [1, 4]
[2, 4], [1, 3]
[2], [1, 3, 4]
[3, 4], [1, 2]
[3], [1, 2, 4]
[4], [1, 2, 3]
>>> len(list(combinations(range(1, 9), 3)))
5796
Related
Here are some examples:
given number: 31
given array: [4, 5, 6, 7]
then the result subset will be [4] or [5] as 31 = 4 * 4 + 3 * 5, the remainder is 0,
but if given number: 31
given array: [4, 5, 6, 7, 8]
then the result subset will be [7, 8] as 31 = 3 * 8 + 1 * 7, the remainder is 0, which is the minimum one.
or if given number: 67
given array: [4, 5, 6, 9, 10, 12]
then the result subset will be [4, 9] as 67 = 7 * 9 + 1 * 4, the remainder is 0, which is the minimum one.
So what I want to ask is that if there is an algorithm to find out such subset from a given array, so that one can get the minimum remainder...
You can consider this task as variant of coin change problem (having sum and some coin nominals, choose the smallest number of coin to compose the sum).
I might be solved with dynamic programming:
Make array A of size sum, fill A[0] with 0, other entries with extreme large value.
For every coin C walk through array.
Intermediate sum i might be composed using coin C and sum i-C, so check
whether adding C to A[i-C] will diminish number of coin nominals used for A[i] and replace A[i] in positive case.
After all A[sum] will contain the smallest number of nominals. If it contain initial large value, scan lesser entries (A[sum-1] and so on).
The Lucas Sequence is a sequence of numbers. The first number of the sequence is 2. The second number of the Lucas Sequence is 1. To generate the next number of the sequence, we add up the previous two numbers. For example, the first six numbers of the sequence are: 2, 1, 3, 4, 7, 11, ...
Write a method lucasSequence that accepts a number representing a length as an arg. The method should return an array containing the Lucas Sequence up to the given length. Solve this recursively.
def lucas_sequence(length)
return [] if length == 0
return [2] if length == 1
return [2, 1] if length == 2
seq = lucas_sequence(length - 1)
next_el = seq[-1] + seq[-2]
seq << next_el
seq
end
p lucas_sequence(0) # => []
p lucas_sequence(1) # => [2]
p lucas_sequence(2) # => [2, 1]
p lucas_sequence(3) # => [2, 1, 3]
p lucas_sequence(6) # => [2, 1, 3, 4, 7, 11]
p lucas_sequence(8) # => [2, 1, 3, 4, 7, 11, 18, 29]
**I'm having a hard time understanding the recursion logic behind this. Can someone explain how the computer is solving this?
Does the computer read the length and then add up from [2,1] until it reaches its length? If so, how does it continuously count down? **
Recursion is the programming equivalent of mathematical induction. Given a series, assume that the problem is solved for the previous member of the series and provide the rule for generating this member.
So, consider just these lines:
def lucas_sequence(length)
seq = lucas_sequence(length - 1) # <1>
next_el = seq[-1] + seq[-2] # <2>
seq << next_el # <3>
seq # <4>
end
That says:
You want to know the lucas sequence of a certain length (length). Fine, first tell me the previous lucas sequence, the sequence that is one unit shorter than this (length-1). (That is the recursion: the lucas_sequence method, itself, calls the lucas_sequence method, but with a reduced length value.)
Add up the last two members of that shorter sequence...
...and append the sum to that shorter sequence...
...and the result is this sequence, the one you asked for.
And that's basically all there is to it! The only problem is that there is no place to start. We assume that for the seq of length 4, we have solved 3 already, which we get by assuming that we have solved 2 already, which we get by assuming we have solve 1 already... But we haven't actually solved any of those!
So we begin by backstopping the most degenerate cases:
return [] if length == 0
return [2] if length == 1
return [2, 1] if length == 2
Now the problem is solved if length is 0, 1, or 2, because we just give those answers directly. Okay, so if length is 3, we solve with reference to 2, which is known. Okay, if length is 4, we solve with reference to 3, and I just told you how to do that. Okay, if length is 5, we solve with reference to 4, and I just told you how to do that. And so on, for any length you care to give me.
So it is essentially a modified Fibonacci sequence. Best way to solve most structured sequences is with an Enumerator e.g.
lucas = Enumerator.new do |y|
a,b = 2,1
loop do
y << a
a, b = b, a + b
end
end
Then
lucas.first(10)
#=> [2, 1, 3, 4, 7, 11, 18, 29, 47, 76]
First we create a new Enumerator and then assign a and b to your starting values (2 and 1 respectively).
To generate the sequence we use a loop which will lazily yield the values to the yielder (y).
Here we push in a then we assign a to bs value and bs value to a + b in parallel to avoid overwriting a before the addition of a + b.
The input is an array of cards. In one move, you can remove any group of consecutive identical cards. For removing k cards, you get k * k points. Find the maximum number of points you can get per game.
Time limit: O(n4)
Example:
Input: [1, 8, 7, 7, 7, 8, 4, 8, 1]
Output: 23
Does anyone have an idea how to solve this?
To clarify, in the given example, one path to the best solution is
Remove Points Total new hand
3 7s 9 9 [1, 8, 8, 4, 8, 1]
1 4 1 10 [1, 8, 8, 8, 1]
3 8s 9 19 [1, 1]
2 1s 4 23 []
Approach
Recursion would fit well here.
First, identify the contiguous sequences in the array -- one lemma of this problem is that if you decide to remove at least one 7, you want to remove the entire sequence of three. From here on, you'll work with both cards and quantities. For instance,
card = [1, 8, 7, 8, 4, 8, 1]
quant = [1, 1, 3, 1, 1, 1, 1]
Now you're ready for the actual solving. Iterate through the array. For each element, remove that element, and add the score for that move.
Check to see whether the elements on either side match; if so, merge those entries. Recur on the remaining array.
For instance, here's the first turn of what will prove to be the optimal solution for the given input:
Choose and remove the three 7's
card = [1, 8, 8, 4, 8, 1]
quant = [1, 1, 1, 1, 1, 1]
score = score + 3*3
Merge the adjacent 8 entries:
card = [1, 8, 4, 8, 1]
quant = [1, 2, 1, 1, 1]
Recur on this game.
Improvement
Use dynamic programming: memoize the solution for every sub game.
Any card that appears only once in the card array can be removed first, without loss of generality. In the given example, you can remove the 7's and the single 4 to improve the remaining search tree.
Sorry for the bad description in the title.
Consider a 2-dimensional list such as this:
list = [
[1, 2],
[2, 3],
[3, 4]
]
If I were to extract all possible "vertical" combinations of this list, for a total of 2*2*2=8 combinations, they would be the following sequences:
1, 2, 3
2, 2, 3
1, 3, 3
2, 3, 3
1, 2, 4
2, 2, 4
1, 3, 4
2, 3, 4
Now, let's say I remove some of these sequences. Let's say I only want to keep sequences which have either the number 2 in position #1 OR number 4 in position #3. Then I would be left with these sequences:
2, 2, 3
2, 3, 3
1, 2, 4
2, 2, 4
1, 3, 4
2, 3, 4
The problem
I would like to re-combine these remaining sequences to the least possible amount of 2-dimensional lists needed to contain all sequences but no less or no more.
By doing so, the resulting 2-dimensional lists in this particular example would be:
list_1 = [
[2],
[2, 3],
[3, 4]
]
list_2 = [
[1],
[2, 3],
[4]
]
In this particular case, the resulting lists can be thought out. But how would I go about if there were thousands of sequences yielding hundereds of 2-dimensional lists? I have been trying to come up with a good algorithm for two weeks now, but I am getting nowhere near a satisfying result.
Divide et impera, or divide and conquer. If we have a logical expression, stating that the value at position x should be a or the value at position y should be b, then we have 3 cases:
a is the value at position x and b is the value at position y
a is the value at position x and b is not the value at position y
a is not the value at position x and b is the value at position y
So, first you generate all your scenarios, you know now that you have 3 scenarios.
Then, you effectively separate your cases and handle all of them in a sub-routine as they were your main tasks. The philosophy behind divide et imera is to reduce your complex problem into several similar, but less complex problems, until you reach triviality.
We have two sorted arrays of the same size n. Let's call the array a and b.
How to find the middle element in an sorted array merged by a and b?
Example:
n = 4
a = [1, 2, 3, 4]
b = [3, 4, 5, 6]
merged = [1, 2, 3, 3, 4, 4, 5, 6]
mid_element = merged[(0 + merged.length - 1) / 2] = merged[3] = 3
More complicated cases:
Case 1:
a = [1, 2, 3, 4]
b = [3, 4, 5, 6]
Case 2:
a = [1, 2, 3, 4, 8]
b = [3, 4, 5, 6, 7]
Case 3:
a = [1, 2, 3, 4, 8]
b = [0, 4, 5, 6, 7]
Case 4:
a = [1, 3, 5, 7]
b = [2, 4, 6, 8]
Time required: O(log n). Any ideas?
Look at the middle of both the arrays. Let's say one value is smaller and the other is bigger.
Discard the lower half of the array with the smaller value. Discard the upper half of the array with the higher value. Now we are left with half of what we started with.
Rinse and repeat until only one element is left in each array. Return the smaller of those two.
If the two middle values are the same, then pick arbitrarily.
Credits: Bill Li's blog
Quite interesting task. I'm not sure about O(logn), but solution O((logn)^2) is obvious for me.
If you know position of some element in first array then you can find how many elements are smaller in both arrays then this value (you know already how many smaller elements are in first array and you can find count of smaller elements in second array using binary search - so just sum up this two numbers). So if you know that number of smaller elements in both arrays is less than N, you should look in to the upper half in first array, otherwise you should move to the lower half. So you will get general binary search with internal binary search. Overall complexity will be O((logn)^2)
Note: if you will not find median in first array then start initial search in the second array. This will not have impact on complexity
So, having
n = 4 and a = [1, 2, 3, 4] and b = [3, 4, 5, 6]
You know the k-th position in result array in advance based on n, which is equal to n.
The result n-th element could be in first array or second.
Let's first assume that element is in first array then
do binary search taking middle element from [l,r], at the beginning l = 0, r = 3;
So taking middle element you know how many elements in the same array smaller, which is middle - 1.
Knowing that middle-1 element is less and knowing you need n-th element you may have [n - (middle-1)]th element from second array to be smaller, greater. If that's greater and previos element is smaller that it's what you need, if it's greater and previous is also greater we need to L = middle, if it's smaller r = middle.
Than do the same for the second array in case you did not find solution for first.
In total log(n) + log(n)