Algorithm to find streets and same kind in a hand - algorithm

This is actually a Mahjong-based question, but a Romme- or even Poker-based background will also easily suffice to understand.
In Mahjong 14 tiles (tiles are like cards in Poker) are arranged to 4 sets and a pair. A street ("123") always uses exactly 3 tiles, not more and not less. A set of the same kind ("111") consists of exactly 3 tiles, too. This leads to a sum of 3 * 4 + 2 = 14 tiles.
There are various exceptions like Kan or Thirteen Orphans that are not relevant here. Colors and value ranges (1-9) are also not important for the algorithm.
I'm trying to determine if a hand can be arranged in the way described above. For certain reasons it should not only be able to deal with 14 but any number of tiles. (The next step would be to find how many tiles need to be exchanged to be able to complete a hand.)
Examples:
11122233344455 - easy enough, 4 sets and a pair.
12345555678999 - 123, 456, 789, 555, 99
11223378888999 - 123, 123, 789, 888, 99
11223344556789 - not a valid hand
My current and not yet implemented idea is this: For each tile, try to make a) a street b) a set c) a pair. If none works (or there would be > 1 pair), go back to the previous iteration and try the next option, or, if this is the highest level, fail. Else, remove the used tiles from the list of remaining tiles and continue with the next iteration.
I believe this approach works and would also be reasonably fast (performance is a "nice bonus"), but I'm interested in your opinion on this. Can you think of alternate solutions? Does this or something similar already exist?
(Not homework, I'm learning to play Mahjong.)

The sum of the values in a street and in a set can be divided by 3:
n + n + n = 3n
(n-1) + n + (n + 1) = 3n
So, if you add together all the numbers in a solved hand, you would get a number of the form 3N + 2M where M is the value of the tile in the pair. The remainder of the division by three (total % 3) is, for each value of M :
total % 3 = 0 -> M = {3,6,9}
total % 3 = 1 -> M = {2,5,8}
total % 3 = 2 -> M = {1,4,7}
So, instead of having to test nine possible pairs, you only have to try three based on a simple addition. For each possible pair, remove two tiles with that value and move on to the next step of the algorithm to determine if it's possible.
Once you have this, start with the lowest value. If there are less than three tiles with that value, it means they're necessarily the first element of a street, so remove that street (if you can't because tiles n+1 or n+2 are missing, it means the hand is not valid) and move on to the next lowest value.
If there are at least three tiles with the lowest value, remove them as a set (if you ask "what if they were part of a street?" consider that if they were, then there are also three of tile n+1 and three of tile n+2, which can also be turned into sets) and continue.
If you reach an empty hand, the hand is valid.
For example, for your invalid hand the total is 60, which means M = {3,6,9}:
Remove the 3: 112244556789
- Start with 1: there are less than three, so remove a street
-> impossible: 123 needs a 3
Remove the 6: impossible, there is only one
Remove the 9: impossible, there is only one
With your second example 12345555678999, the total is 78, which means M = {3,6,9}:
Remove the 3: impossible, there is only one
Remove the 6: impossible, there is only one
Remove the 9: 123455556789
- Start with 1: there is only one, so remove a street
-> 455556789
- Start with 4: there is only one, so remove a street
-> 555789
- Start with 5: there are three, so remove a set
-> 789
- Start with 7: there is only one, so remove a street
-> empty : hand is valid, removals were [99] [123] [456] [555] [789]
Your third example 11223378888999 also has a total of 78, which causes backtracking:
Remove the 3: 11227888899
- Start with 1: there are less than three, so remove a street
-> impossible: 123 needs a 3
Remove the 6: impossible, there are none
Remove the 9: 112233788889
- Start with 1: there are less than three, so remove streets
-> 788889
- Start with 7: there is only one, so remove a street
-> 888
- Start with 8: there are three, so remove a set
-> empty, hand is valid, removals were : [99] [123] [123] [789] [888]

There is a special case that you need to do some re-work to get it right. This happens when there is a run-of-three and a pair with the same value (but in different suit).
Let b denates bamboo, c donates character, and d donates dot, try this hand:
b2,b3,b4,b5,b6,b7,c4,c4,c4,d4,d4,d6,d7,d8
d4,d4 should serve as the pair, and c4,c4,c4 should serve as the run-of-3 set.
But because the 3 "c4" tiles appear before the 2 d4 tiless, the first 2 c4 tiles will be picked up as the pair, leaving an orphan c4 and 2 d4s, and these 3 tiles won't form a valid set.
In this case, you'll need to "return" the 2 c4 tiles back to the hand (and keep the hand sorted), and search for next tile that meets the criteria (value == 4). To do that you'll need to make the code "remember" that it had tried c4 so in next iteration it should skip c4 and looks for other tiles with value == 4. The code will be a bit messy, but doable.

I would break it down into 2 steps.
Figure out possible combinations. I think exhaustive checking is feasible with these numbers. The result of this step is a list of combinations, where each combination has a type (set, street, or pair) and a pattern with the cards used (could be a bitmap).
With the previous information, determine possible collections of combinations. This is where a bitmap would come in handy. Using bitwise operators, you could see overlaps in usage of the same tile for different combinators.
You could also do a step 1.5 where you just check to see if enough of each type is available. This step and step 2 would be where you would be able to create a general algorithm. The first step would be the same for all numbers of tiles and possible combinations quickly.

Related

Split array into four boxes such that sum of XOR's of the boxes is maximum

Given an array of integers which are needed to be split into four
boxes such that sum of XOR's of the boxes is maximum.
I/P -- [1,2,1,2,1,2]
O/P -- 9
Explanation: Box1--[1,2]
Box2--[1,2]
Box3--[1,2]
Box4--[]
I've tried using recursion but failed for larger test cases as the
Time Complexity is exponential. I'm expecting a solution using dynamic
programming.
def max_Xor(b1,b2,b3,b4,A,index,size):
if index == size:
return b1+b2+b3+b4
m=max(max_Xor(b1^A[index],b2,b3,b4,A,index+1,size),
max_Xor(b1,b2^A[index],b3,b4,A,index+1,size),
max_Xor(b1,b2,b3^A[index],b4,A,index+1,size),
max_Xor(b1,b2,b3,b4^A[index],A,index+1,size))
return m
def main():
print(max_Xor(0,0,0,0,A,0,len(A)))
Thanks in Advance!!
There are several things to speed up your algorithm:
Build in some start-up logic: it doesn't make sense to put anything into box 3 until boxes 1 & 2 are differentiated. In fact, you should generally have an order of precedence to keep you from repeating configurations in a different order.
Memoize your logic; this avoids repeating computations.
For large cases, take advantage of what value algebra exists.
This last item may turn out to be the biggest saving. For instance, if your longest numbers include several 5-bit and 4-bit numbers, it makes no sense to consider shorter numbers until you've placed those decently in the boxes, gaining maximum advantage for the leading bits. With only four boxes, you cannot have a num from 3-bit numbers that dominates a single misplaced 5-bit number.
Your goal is to place an odd number of 5-bit numbers into 3 or all 4 boxes; against this, check only whether this "pessimizes" bit 4 of the remaining numbers. For instance, given six 5-digit numbers (range 16-31) and a handful of small ones (0-7), your first consideration is to handle only combinations that partition the 5-digit numbers by (3, 1, 1, 1), as this leaves that valuable 5-bit turned on in each set.
With a more even mixture of values in your input, you'll also need to consider how to distribute the 4-bits for a similar "keep it odd" heuristic. Note that, as you work from largest to smallest, you need worry only about keeping it odd, and watching the following bit.
These techniques should let you prune your recursion enough to finish in time.
We can use Dynamic programming here to break the problem into smaller sets then store their result in a table. Then use already stored result to calculate answer for bigger set.
For example:
Input -- [1,2,1,2,1,2]
We need to divide the array consecutively into 4 boxed such that sum of XOR of all boxes is maximised.
Lets take your test case, break the problem into smaller sets and start solving for smaller set.
box = 1, num = [1,2,1,2,1,2]
ans = 1 3 2 0 1 3
Since we only have one box so all numbers will go into this box. We will store this answer into a table. Lets call the matrix as DP.
DP[1] = [1 3 2 0 1 3]
DP[i][j] stores answer for distributing 0-j numbers to i boxes.
now lets take the case where we have two boxes and we will take numbers one by one.
num = [1] since we only have one number it will go into the first box.
DP[1][0] = 1
Lets add another number.
num = [1 2]
now there can be two ways to put this new number into the box.
case 1: 2 will go to the First box. Since we already have answer
for both numbers in one box. we will just use that.
answer = DP[0][1] + 0 (Second box is empty)
case 2: 2 will go to second box.
answer = DP[0][0] + 2 (only 2 is present in the second box)
Maximum of the two cases will be stored in DP[1][1].
DP[1][1] = max(3+0, 1+2) = 3.
Now for num = [1 2 1].
Again for new number we have three cases.
box1 = [1 2 1], box2 = [], DP[0][2] + 0
box1 = [1 2], box2 = [1], DP[0][1] + 1
box1 = [1 ], box2 = [2 1], DP[0][0] + 2^1
Maximum of these three will be answer for DP[1][2].
Similarly we can find answer of num = [1 2 1 2 1 2] box = 4
1 3 2 0 1 3
1 3 4 6 5 3
1 3 4 6 7 9
1 3 4 6 7 9
Also note that a xor b xor a = b. you can use this property to get xor of a segment of an array in constant time as suggested in comments.
This way you can break the problem in smaller subset and use smaller set answer to compute for the bigger ones. Hope this helps. After understanding the concept you can go ahead and implement it with better time than exponential.
I would go bit by bit from the highest bit to the lowest bit. For every bit, try all combinations that distribute the still unused numbers that have that bit set so that an odd number of them is in each box, nothing else matters. Pick the best path overall. One issue that complicates this greedy method is that two boxes with a lower bit set can equal one box with the next higher bit set.
Alternatively, memoize the boxes state in your recursion as an ordered tuple.

How to calculate how many bit sequences of size n with k bits set and c changes of bit values exist?

We know that calculating the number of n-length bit sequences with k bits set is equal to C(n,k)=n!/(k!(n-k)!)*.
But I've recently asked myself how can you think about this problem once another condition is set: The number of bit value changes. For instance, for n=4 and k=2 we have 6 solutions:
1-0011
2-0101
3-0110
4-1001
5-1010
6-1100
Now suppose we only want to get the sequences with two changes in bit values. Now there are only two solutions:
1-0110 (begins with 0, changes to 1, than changes to 0 after).
2-1001 (begins with 1, changes to 0, than changes to 1 after).
How can I quickly calculate the number of solutions(without generating every combination and counting)? I think one could count the initial bit as a change without changing the answer too much, so feel free to do it.
Extra question: Given a combination with k bits set and c number of bit changes, what is the quickest way to generate the next combination with the same amount of k bits set and c number of bit changes?
This is a balls-and-urns problem. You start with a sequence of alternating 0s and 1s with the required number of bit changes, and then you place the remaining 0s and 1s into the urns.
Example: n=20, k=8, c=4.
Consider the case where the bistring starts with 0. Start with (c+1) alternating bits, to get your c changes:
01010
At this point you still need to place 9 0s and 6 1s. Let's place the 0s first. How many ways can we place the 9 remaining 0s, without adding any bit changes? There are 3 "urns" to place the "balls" (0s):
0 ... 1 0 ... 1 0 ...
^ ^ ^
There are (9+3-1) choose 3 ways of placing 9 balls into 3 urns.
Once the 0s are placed, we also need to place the 1s. By similar reasoning, we have 6 balls (1s) to place in 2 urns, which can be done in (6+2-1) choose 2 ways.
Since the arrangement of 0s and 1s are independent, we multiply the results: there are ((9+3-1) choose 3) * ((6+2-1) choose 2) ways for a length-20 bitstring with 8 1s to have 4 bit changes, assuming you start with 0.
You still need to add the remaining case (starting with 1, so the first step results in 10101), which can be solved in exactly the same way.
Suppose we have a row of n indistinguishable objects, say red balls. How many ways can we divide them into k non-empty groups? That's pretty easy, right? The first group starts with the first object, and every other group has to start at some different object. So we can construct a partition by choosing the first object and k-1 of the n-1 remaining objects, which we can do in C(n-1, k-1) different ways.
Now suppose we have another row of m indistinguishable objects, say blue balls, and we want to divide them into j groups. But that's exactly the same problem, and the solution must be C(m-1, j-1).
OK, now suppose we want to construct a row of objects, of which n are red and m are blue, in which there are a total of c groups alternating between red and blue. Now, there are two possibilities:
The row will start with a red ball. If c is even, then there will be c/2 red groups interleaved with c/2 blue groups. If c is odd, there will be one more red group than blue group, so there will be ceil(c/2) red groups and floor(c/2) blue groups. (If c is even then both floor(c/2) and ceil(c/2) are exactly c/2. So we can use the floor and ceil formulas in both cases.)
In any event, we can divide the red balls into groups and the blue balls into groups independently, and then interleave them. So there are C(n - 1, ceil(c/2) - 1) × C(m - 1, floor(c/2) - 1) possible arrangements.
The row will start with a blue ball. Exactly the same analysis applies, except that n and m are reversed.
So the total number of arrangements is:
C(n - 1, ceil(c/2) - 1) × C(m - 1, floor(c/2) - 1) +
C(n - 1, floor(c/2) - 1) × C(m - 1, ceil(c/2) - 1)
This is just a rewriting of your problem, which had k ones and n-k zeros, with c-1 transitions (which leads to c groups). I'll leave the remaining algebra step to the reader (as well as the simplification for odd group counts).

Improve a working "Bulgarian Solitaire" J verb

"Bulgarian Solitaire" is a mathematical curiosity. It is played with a deck of 45 (any triangular number will work) unmarked cards. Put them into randomly sized piles. Then, to play a round, remove a card from each pile and create a new pile with the removed cards. Repeating this step eventually yields the configuration 1 2 3 4 5 6 7 8 9 (for 45 cards), which is clearly a fixed point of the game and thus the end of the solitaire. I wanted to simulate this game in J.
After a couple of days thinking about it and some long-awaited insight into J gerunds, I came up with a solution, on which I would like some opinions. It starts with this verb:
bsol =: ((#~ ~:&0) , #)#:(-&1)^:(<_)
Given a vector of positive integers whose sum is triangular, this verb returns a rank 2 array showing the rounds of the solitaire that results. I also came up with this verb to generate an initial configuration, but I'm less happy with it:
t =: 45 & - # (+/) NB. Would work with any triangular number
cards =: (]`(]#,>:#?&t#]))#.(0&<#t)^:_
Given a vector y of positive integers, t returns the defect from 45, i.e., the number 45 - +/ y of cards not accounted for in the piles represented by the argument. Using t, the verb cards appends to such a vector y an integer from >: i. t y repeatedly until the defect is 0.
Expanding t explicitly, I get
cards =: (]`(]#,>:#?&(45 & - # (+/))#]))#.(0&<#(45 & - # (+/)))^:_
I feel like this is not very brief, and maybe overly parenthesized. But it does work, and the complete solution now looks like this:
bsol # cards # >: # ? 44 NB. Choose the first pile randomly from >: i. 44
Without the named verbs:
(((#~ ~:&0) , #)#:(-&1)^:(<_)) #: ((]`(]#,>:#?&(45 & - # (+/))#]))#.(0&<#(45 & - # (+/)))^:_)#>:#? 44
Not knowing much about J idiom, I have the same feeling about this: it's not very brief, certainly redundant (would it be better to use a local verb like t here, since it's repeated, e.g.?), and probably overly parenthesized. What opportunities do I have to improve this program?
You can improve t with
t =: 45 - +/
Using 46 - +/ will spare you some >:.
You can replace cards with a recursive definition:
cards =: }.`(($:#] , -) ?)#.(0&<)
where, now, cards n produces an initial configuration with sum n.
In bsol you don't need -&1 if you remove (-.) the zeroes and rearrange it like:
bsol =: (0 -.~ [: (, #) <:)^:(<_)

Count ways to take atleast one stick

There are N sticks placed in a straight line. Bob is planning to take few of these sticks. But whatever number of sticks he is going to take, he will take no two successive sticks.(i.e. if he is taking a stick i, he will not take i-1 and i+1 sticks.)
So given N, we need to calculate how many different set of sticks he could select. He need to take at least stick.
Example : Let N=3 then answer is 4.
The 4 sets are: (1, 3), (1), (2), and (3)
Main problem is that I want solution better than simple recursion. Can their be any formula for it? As am not able to crack it
It's almost identical to Fibonacci. The final solution is actually fibonacci(N)-1, but let's explain it in terms of actual sticks.
To begin with we disregard from the fact that he needs to pick up at least 1 stick. The solution in this case looks as follows:
If N = 0, there is 1 solution (the solution where he picks up 0 sticks)
If N = 1, there are 2 solutions (pick up the stick, or don't)
Otherwise he can choose to either
pick up the first stick and recurse on N-2 (since the second stick needs to be discarded), or
leave the first stick and recurse on N-1
After this computation is finished, we remove 1 from the result to avoid counting the case where he picks up 0 sticks in total.
Final solution in pseudo code:
int numSticks(int N) {
return N == 0 ? 1
: N == 1 ? 2
: numSticks(N-2) + numSticks(N-1);
}
solution = numSticks(X) - 1;
As you can see numSticks is actually Fibonacci, which can be solved efficiently using for instance memoization.
Let the number of sticks taken by Bob be r.
The problem has a bijection to the number of binary vectors with exactly r 1's, and no two adjacent 1's.
This is solveable by first placing the r 1's , and you are left with exactly n-r 0's to place between them and in the sides. However, you must place r-1 0's between the 1's, so you are left with exactly n-r-(r-1) = n-2r+1 "free" 0's.
The number of ways to arrange such vectors is now given as:
(1) = Choose(n-2r+1 + (r+1) -1 , n-2r+1) = Choose(n-r+1, n-2r+1)
Formula (1) is deriving from number of ways of choosing n-2r+1
elements from r+1 distinct possibilities with replacements
Since we solved it for a specific value of r, and you are interested in all r>=1, you need to sum for each 1<=r<=n
So, the solution of the problem is given by the close formula:
(2) = Sum{ Choose(n-r+1, n-2r+1) | for each 1<=r<=n }
Disclaimer:
(A close variant of the problem with fixed r was given as HW in the course I am TAing this semester, main difference is the need to sum the various values of r.

Algorithm(s) / approach

Recently I came across this question and I have no clue where or how to start solving it. Here is the question:
There are 8 statues 0,1,2,3,4,5,6,7 . Each statue is pointing in one of the following four direction North, South, East or West. John would like to arrange the statues so that they all point in same direction. However John is restricted to the following 8 moves which correspond to rotation each statue listed 90 degrees clockwise. (N to E, E to S, S to W, W to N)
Moves
A: 0,1
B: 0,1,2
C: 1,4,5,6
D: 2,5
E: 3,5
F: 3,7
G: 5,7
H: 6,7
Help John figure out fewest number of moves to help point all statues in one direction.
Input : A string initialpos consisting of 8 chars. Each char is either 'N,'S,'E,'W'
Output: An integer which represents fewest no. of moves needed to arrange statues in same direction. If no sequence possible then return -1.
Sample test cases:
input: SSSSSSSS
Output: 0
Explanation: All statues point in same direction. So it takes 0 moves
Test case 1:
Input : WWNNNNNN
Output: 1
Exp: John can use Move A which will make all statues point to North
Test Case 3:
input: NNSEWSWN
Output: 6
Exp: John uses Move A twice, B once, F twice, G once. This will result in all statues facing W.
The only approach I was able to think of was to brute force it. But since the moves can be done multiple times (test case 3), what would be the limit to applying the moves before we conclude that such an arrangement is not possible (i.e output -1)? I am looking for specific types of algorithms that can be used to solve this, also what part of the problem is used in identifying an algorithm.
Note that the order of moves makes no difference, only the set (with repetition). Also note that making the same move 4 times is equivalent to doing nothing, so there is never any reason to make the same move more than 3 times. This reduces the space to 48 possible sequences, which isn't too terrible, but we can still do better than brute force.
The only move that treats 0 and 1 differently is C, so apply C as many times as is necessary to bring 0 and 1 into alignment. We mustn't use C any more than that, and C is the only thing that can move 4, so the remaining task is to align everything to 4.
The only way to move 6 is with H; apply H to align 6.
Now to align 3 and 7. We could do it with E and G, but we may have the option to use F as a short-cut. The optimal number of F moves is not yet clear, so we'll use E and G, and come back to F later.
Apply D to align 5.
Apply B to align 2.
Apply A to align 0 and 1.
Now revisit F, and see whether the short-cut actually saves moves. Pick the optimal number of F moves. (This is easy even by brute force, since there are only 4 possibilities to test.)
The directions N, E, W, S with operation of turning are congruent with Z mod 4 with succ: turn N = (succ 0) mod 4, turn W twice = (succ succ 2) mod 4 etc.
Each move is a vector of zeros (no change) and ones (turn by one) being added to inputs: say you have your example of NNSEWSWN, which would be [0, 0, 2, 1, 3, 2, 3, 0], and you push the button A, which is [1, 1, 0, 0, 0, 0, 0, 0], resulting in [1, 1, 2, 1, 3, 2, 3, 0], or EESEWSWN.
Now if you do a bunch of different operations, they all add up. Thus, you can represent the whole system with this matrix equation:
(start + move_matrix * applied_moves) mod 4 = finish
where start and finish are position vectors as described above, move_matrix the 8x8 matrix with all the moves, and applied_moves a 8-element vector saying how many times we push each button (in range 0..3).
From this, you can get:
applied_moves = (inverse(move_matrix) * (finish - start)) mod 4
Number of applied moves is then just this:
num_applied_moves = sum((inverse(move_matrix) * (finish - start)) mod 4)
Now just plug in the four different values for finish and see which one is least.
You can use matlab, numpy, octave, APL, whatever rocks your boat, as long as it supports matrix algebra, to get your answer very quickly and very easily.
This sounds a little like homework... but I would go with this line of logic.
Run a loop seeing how many moves it would take to move all the statues to face one direction. You would get something like allEast = 30, allWest = 5, etc. Take the lowest sum and corresponding direction would be the answer. With that mindset its pretty easy to build an algorithm to handle computation.
Brute-force could work. A move applied 4 times is the same as not applying the move at all, so each move can only be applied 0, 1, 2, or 3 times.
The order of the moves does not matter. Move a followed by b is the same as b followed by a.
So there are only 4^8 = 65536 possible combinations of moves.
A general solution is to note that there are only 4^8 = 64k different configurations. Each move can therefore be represented as a table of 64k 2 byte indices taking one configuration to the next. The 2 bytes e.g. are divided into 8 2-bit fields 0=N, 1=E, 2=S, 3=W. Further we can use one more table of bits to say which of the 64k configurations have all statues pointing in the same direction.
These tables don't need to be computed at run time. They can be preprocessed while writing the program and stored.
Let table A[c] give the configuration resulting after applying move A to configuration c. and Z[c] return true iff c is a successful config.
So we can use a kind of BFS:
1. Let C be a set of configurations, initially C = { s } where s is the starting config
2. Let n = 0
3. If Z[c] is true for any c in C, return n
4. Let C' be the result of applying A, B, ... H to each element of C.
5. Set C = C', n = n + 1 and go to 3
C can theoretically grow to be almost 64k in size, but the bigger it gets, the better the chances of success, so this ought to be quite fast in practice.

Resources