I'm trying to solve one of the Project Euler problems. As a consequence, I need an algorithm that will help me find all possible partitions of a set, in any order.
For instance, given the set 2 3 3 5:
2 | 3 3 5
2 | 3 | 3 5
2 | 3 3 | 5
2 | 3 | 3 | 5
2 5 | 3 3
and so on. Pretty much every possible combination of the members of the set. I've searched the net of course, but haven't found much that's directly useful to me, since I speak programmer-ese not advanced-math-ese.
Can anyone help me out with this? I can read pretty much any programming language, from BASIC to Haskell, so post in whatever language you wish.
Have you considered a search tree? Each node would represent a choice of where to put an element and the leaf nodes are answers. I won't give you code because that's part of the fun of Project Euler ;)
Take a look at:
The Art of Computer Programming, Volume 4, Fascicle 3: Generating All Combinations and Partitions
7.2.1.5. Generating all set partitions
In general I would look at the structure of the recursion used to compute the number of configurations, and build a similar recursion for enumerating them. Best is to compute a one-to-one mapping between integers and configurations. This works well for permutations, combinations, etc. and ensures that each configuration is enumerated only once.
Now even the recursion for the number of partitions of some identical items is rather complicated.
For partitions of multisets the counting amounts to solving the generalization of Project Euler problem 181 to arbitrary multisets.
Well, the problem has two aspects.
Firsty, the items can be arranged in any order. So for N items, there are N! permutations (assuming the items are treated as unique).
Secondly, you can envision the grouping as a bit flag between each item indicating a divide. There would be N-1 of these flags, so for a given permutation there would be 2^(N-1) possible groupings.
This means that for N items, there would be a total of N!*(2^(N-1)) groupings/permutations, which gets big very very fast.
In your example, the top four items are groupings of one permutation. The last item is a grouping of another permutation. Your items can be viewed as :
2 on 3 off 3 off 5
2 on 3 on 3 off 5
2 on 3 off 3 on 5
2 on 3 on 3 on 5
2 off 5 on 3 off 3
The permutations (the order of display) can be derived by looking at them like a tree, as mentioned by the other two. This would almost certainly involve recursion, such as here.
The grouping is independent of them in many ways. Once you have all the permutations, you can link them with the groupings if needed.
Here is the code you need for this part of your problem:
def memoize(f):
memo={}
def helper(x):
if x not in memo:
memo[x]=f(x)
return memo[x]
return helper
#memoize
def A000041(n):
if n == 0: return 1
S = 0
J = n-1
k = 2
while 0 <= J:
T = A000041(J)
S = S+T if k//2%2!=0 else S-T
J -= k if k%2!=0 else k//2
k += 1
return S
print A000041(100) #the 100's number in this series, as an example
I quickly whipped up some code to do this. However, I left out separating every possible combination of the given list, because I wasn't sure it was actually needed, but it should be easy to add, if necessary.
Anyway, the code runs quite well for small amounts, but, as CodeByMoonlight already mentioned, the amount of possibilities gets really high really fast, so the runtime increases accordingly.
Anyway, here's the python code:
import time
def separate(toseparate):
"Find every possible way to separate a given list."
#The list of every possibility
possibilities = []
n = len(toseparate)
#We can distribute n-1 separations in the given list, so iterate from 0 to n
for i in xrange(n):
#Create a copy of the list to avoid modifying the already existing list
copy = list(toseparate)
#A boolean list indicating where a separator is put. 'True' indicates a separator
#and 'False', of course, no separator.
#The list will contain i separators, the rest is filled with 'False'
separators = [True]*i + [False]*(n-i-1)
for j in xrange(len(separators)):
#We insert the separators into our given list. The separators have to
#be between two elements. The index between two elements is always
#2*[index of the left element]+1.
copy.insert(2*j+1, separators[j])
#The first possibility is, of course, the one we just created
possibilities.append(list(copy))
#The following is a modification of the QuickPerm algorithm, which finds
#all possible permutations of a given list. It was modified to only permutate
#the spaces between two elements, so it finds every possibility to insert n
#separators in the given list.
m = len(separators)
hi, lo = 1, 0
p = [0]*m
while hi < m:
if p[hi] < hi:
lo = (hi%2)*p[hi]
copy[2*lo+1], copy[2*hi+1] = copy[2*hi+1], copy[2*lo+1]
#Since the items are non-unique, some possibilities will show up more than once, so we
#avoid this by checking first.
if not copy in possibilities:
possibilities.append(list(copy))
p[hi] += 1
hi = 1
else:
p[hi] = 0
hi += 1
return possibilities
t1 = time.time()
separations = separate([2, 3, 3, 5])
print time.time()-t1
sepmap = {True:"|", False:""}
for a in separations:
for b in a:
if sepmap.has_key(b):
print sepmap[b],
else:
print b,
print "\n",
It's based on the QuickPerm algorithm, which you can read more about here: QuickPerm
Basically, my code generates a list containing n separations, inserts them into the given list and then finds all possible permutations of the separations in the list.
So, if we use your example we would get:
2 3 3 5
2 | 3 3 5
2 3 | 3 5
2 3 3 | 5
2 | 3 | 3 5
2 3 | 3 | 5
2 | 3 3 | 5
2 | 3 | 3 | 5
In 0.000154972076416 seconds.
However, I read through the problem description of the problem you are doing and I see how you are trying to solve this, but seeing how quickly the runtime increases I don't think that it would work as fast you would expect. Remember that Project Euler's problems should solve in around a minute.
Related
You're given an array of integers A. You keep doing iterations of the following until the array stops changing: if an element is larger than both of its adjacent neighbors, decrement it by 1. If an element is smaller than both of its adjacent neighbors, increment it by 1. Return the final state of the array (when it will not change any more). Note that the first and last elements do not have two neighbors, so they will never change.
Example: [1,2,7,4,6] -> [1,2,6,5,6] ->[1,2,5,6,6]
Example: [1,2,3,4] Does not change
Anyone have an idea of how to do this better than simulation? I feel like there should be an O(n) solution, but I can't think of it.
You can calculate teh differnce between all numbers. For your series:
1 , 2 , 7 , 4 , 6 you get
1 5 -3 2
you can conclude that a sign change from + to - means a decrease of the number and from - to + and increase
You also can conclude that 7 can be decreased min(abs(5), abs(-3)) = 3 times max before it "hits its boundry" what is 4. Problem is that 4 changes with the first iteration. This you can recognize by the 2 sequential sign changes. So when this is happening, your max before hitting the boudry for 7 becomes: min(abs(5), ceiling(abs(-3)/2)) = 2
as the max of hitting the boundy on 4 becomes min(ceiling(abs(-3)/2), abs(2)) = 2
With the knowledge above, you know you need to deduct: 7 - 2 = 5 and increase 4 + 2 = 6 to get your answer.
The question is what is the smallest possible value of N so R= 41441? I did the problem and the result is 1234 but I am curious if there is an easier and faster way to do such problems. What I did is simulate the algorithm running in my head from the end to beginning until I get the first number which is also the answer. TBD the last number that gets run in the flow is 1 because 1 div 5 is 0 and 1 mod 5 is 1 which is the final number of R, then the number before that that was ran was 9 because 9 mod 5 is 4 which is the second last number of R and 9 div 5 is 1 which is the next number that runs in the flow. I kept on doing that until I made it to the final number which is 1234 and gives me all the numbers I need for R: 41441.
Are there any clever methods for doing these problems in a more efficient way?
The problem of finding N is equivalent to the problem of finding the conversion to base 10 of the number in base 5 "14414" which is the string R reversed. This just follows from what a base b representation is, and what the fact that if you have a number N in base b, N mod b just gives you the last digit, and N div b gives you the number with the last digit chopped of.
Given q queries of the following form. A list is there.
1 x y: Add number x to the list y times.
2 n: find the nth number of the sorted list
constraints
1 <= q <= 5 * 100000
1 <= x, y <= 1000000000
1 <= n < length of list
sample.
input
4
1 3 6
1 5 2
2 7
2 4
output
5
3
This is a competitive programming problem that it's too early in the morning for me to solve right now, but I can try and give some pointers.
If you were to store the entire array explicitly, it would obviously blow out your memory. But you can exploit the structure of the array to instead store the number of times each entry appears in the array. So if you got the query
1 3 5
then instead of storing [3, 3, 3], you'd store the pair (3, 5), indicating that the number 3 is in the list 5 times.
You can pretty easily build this, perhaps as a vector of pairs of ints that you update.
The remaining task is to implement the 2 query, where you find an element by its index. A side effect of the structure we've chosen is that you can't directly index into that vector of pairs of ints, since the indices in that list don't match up with the indices into the hypothetical array. We could just add up the size of each entry in the vector from the start until we hit the index we want, but that's O(n^2) in the number of queries we've processed so far... likely too slow. Instead, we probably want some updatable data structure for prefix sums—perhaps as described in this answer.
So here is an interesting problem in C#. I'm looking for a better way of solving it:
Given a matrix M (not necesarily square) of matches, find the best matching elements. Element i matches elem j by value M(i,j). M(i,j) != M(j,i).
Since #rows != #columns, find the best min(#rows,#columns) matching pairs (i,j).
Basically the problem is to pick the maximum from each row/column such that no row/column is picked twice.
Example:
1 2 3
+---------
a | 10 3 1
b | 12 99 2
c | 20 5 3
d | 5 7 4
The maximum value in this matrix is 99 so the best match is (b,2). For the next selection we cannot use anymore row b and column 2. Is like cutting them
1 2 3 or, if you prefer, 1 3
+--------- a smaller matrix: +------
a | 10 || 1 a | 10 1
b | ===++=== c | 20 3
c | 20 || 3 d | 5 4
d | 5 || 4
The max is now 20 and the match is (c, 1). The remaining matrix has only one column.
After another pick we'll get the match (d, 3) with match = 4
In the end "a" has no match.
My current implementation uses 2 array to store the already matched rows/columns and for each match goes through the entire matrix, picking the first maximum that belongs to row/col not match.
PS: in case of value multiple matches having the same value, just pick one of them
PS2: The array is stored as int [,]
How would you approach this problem in a more optimal/beautiful way?
If you are trying to maximise the sum of the cells chosen, such that exactly one cell is picked from each row and from each column, then this is http://en.wikipedia.org/wiki/Assignment_problem. If your matrix is not square, you can make it square by adding rows or columns to them, with values in the new cells which mean that they won't be picked unless there is no other way to fill out the solution.
(If you are not maximising the sum, you need to say what function of the values chosen you are maximising - is (1,3) better than (2,2)?. Otherwise you are into http://en.wikipedia.org/wiki/Multi-objective_optimization, which is possible, but more complicated).
You could first sort all of the entries of the matrix in descending order, and then process the sorted list. Whenever you see an entry that isn't in an already-picked row/col, it means that entry should be picked, so you mark the corresponding row/column and continue further down the list until either all rows or all columns have been picked.
I recently gathered, using a questionnaire, a set of opinions on the importance of various software components. Figuring that some form of Condorcet voting method would be the best way to obtain an overall rank, I opted to use OpenSTV to analyze it.
My data is in tabular format, space delimited, and looks more or less like:
A B C D E F G # Candidates
5 2 4 3 7 6 1 # First ballot. G is ranked first, and E is ranked 7th
4 2 6 5 1 7 3 # Second ballot
etc
In this format, the number indicates the rank and the sequence order indicates the candidate.
Each "candidate" has a rank (required) from 1 to 7, where a 1 means most important and a 7 means least important. No duplicates are allowed.
This format struck me as the most natural way to represent the output, being a direct representation of the ballot format.
The OpenSTV/BLT format uses a different method of representing the same info, conceptually as follows:
G B D C A F E # Again, G is ranked first and E is ranked 7th
E B G A D C F #
etc
The actual numeric file format uses the (1-based) index of the candidate, rather than the label, and so is more like:
7 2 4 3 1 6 5 # Same ballots as before.
5 2 7 1 4 3 6 # A -> 1, G -> 7
In this format, the number indicates the candidate, and the sequence order indicates the rank. The actual, real, BLT format also includes a leading weight and a following zero to indicate the end of each ballot, which I don't care too much about for this.
My question is, what is the most elegant way to convert from the first format to the (numeric) second?
Here's my solution in Python, and it works ok but feels a little clumsy. I'm sure there's a cleaner way(perhaps in another language?)
This took me longer than it should have to wrap my head around yesterday afternoon, so maybe somebody else can use this too.
Given:
ballot = '5 2 4 3 7 6 1'
Python one(ish)-liner to convert it:
rank = [i for r,i in sorted((int(r),i+1) for i,r in enumerate(ballot.split())]
rank = " ".join(rank)
Alternatively, in a slightly more understandable form:
# Split into a list and convert to integers
int_ballot = [int(x) for x in ballot.split()]
# This is the important bit.
# enumerate(int_ballot) yields pairs of (zero-based-candidate-index, rank)
# Use a list comprehension to swap to (rank, one-based-candidate-index)
ranked_ballot = [(rank,index+1) for index,rank in enumerate(int_ballot)]
# Sort by the ranking. Python sorts tuples in lexicographic order
# (ie sorts on first element)
# Use a comprehension to extract the candidate from each pair
rank = " ".join([candidate for rank,candidate in sorted(ranked_ballot)])