I got a brain teaser for you – it’s not as simple as it sounds so please read and try to solve the issue. Before you ask if it’s homework – it’s not! I just wish to see if there’s an elegant way of solving this. Here’s the issue:
X-number of friends want’s to go to the cinema and wish to be seated
in the best available groups. Best case is that everyone sits together
and worst case is that everyone sits alone. Fewer groups are preferred over more groups. Ballanced groups are preferred (3+3 is more preferred than 4+2).
Sitting alone is least preferred.
Input is the number of people going to the cinema and output should be an array of integer arrays that contains:
- Ordered combinations (most preferred are first)
- Number of people in each group
Below are some examples of number of people going to the cinema and a list of preferred combinations these people can be seated:
- 1 person: 1
- 2 persons: 2, 1+1
- 3 persons: 3, 2+1, 1+1+1
- 4 persons: 4, 2+2, 3+1, 2+1+1, 1+1+1+1
- 5 persons: 5, 3+2, 4+1, 2+2+1, 3+1+1, 2+1+1+1, 1+1+1+1+1
- 6 persons: 6, 3+3, 4+2, 2+2+2, 5+1, 3+2+1, 2+2+1+1, 2+1+1+1+1, 1+1+1+1+1+1
Example with more than 7 persons explodes in combinations but I think you get the point by now.
Question is: What does an algorithm look like that solves this problem?
My language by choice is C# so if you could give an answer in C# it would be fantastic!
I think you need to do it recursively but you need to make sure that you don’t keep partitioning the same group over and over again. This will give you exponential execution time. In my solution it looks I have O(n*n) (you can verify it for me 😉 , see the results below. Another thing is the desirablity function you mention. I don’t know how such a function could look like, but you can instead compare 2 partitions. e.g. partition 1 + 1 + 2 + 4 is less desirable then 1 + 2 + 2 + 3 because it has two ‘ones’. A general rule could be ‘a partition is less desirable if it has more of the same number of people grouped than another partition’. Makes sense, the more people sit together, the better. My solution takes this approach for comparing 2 possible groupings and I get the result that you wanted to achieve. Let me show you some results first, then the code.
1 person: 1
2 persons: 2, 1+1
3 persons: 3, 1+2, 1+1+1
4 persons: 4, 2+2, 1+3, 1+1+2, 1+1+1+1
5 persons: 5, 2+3, 1+4, 1+2+2, 1+1+3, 1+1+1+2, 1+1+1+1+1
6 persons: 6, 3+3, 2+4, 2+2+2, 1+5, 1+2+3, 1+1+4, 1+1+2+2, 1+1+1+3, 1+1+1+1+2, 1+1+1+1+1+1
performance looks to be O(n*n):
Let me post now the 3 classes involved in the solution:
Now to the solution:
The brainteaser class does the recursion. One trick in this class is to use a custom comparer (
PossibleGroupingComparer) in the hashset. This will make sure that when we calculate new groupings (e.g. 1+1+2 vs 2+1+1), those will be treated as the same (our set will contain only one representant for each equivalent grouping). This should reduce exponential runtime to O(n^2).The next trick is that ordering the result is possible because our
PossibleGroupingsclass implements IComparable. The implementation of the Compare() method uses the idea mentioned above. This method essentially contains the salt in this solution and if you want to have it grouped differently you should only modify this method.I hope you can understand the code otherwise let me know. I tried to make it readable and didn’t care much about performance. You could for instance order the groupings only before you return them to the caller, the ordering within the recursions doesn’t bring much.
One comment though: A typical scenario might be that a cinema has ‘already’ booked many seats and won’t allow for ‘any’ partition. Here you need to get all partitions and then check one-by-one if it’s possible to use for the current cinema. That works, but costs unnecessary CPU. Instead, we could use the input to reduce the number of recursions and improve the overall execution time. Maybe someone wants to post a solution for this 😉