Toilet Seat Algorithm - algorithm

Let's take some regular house with a man, which has to go to the toilet every n minutes, requiring the seat to be up, and a woman, which has to do it every m minutes, requiring a seat to be down. Is there a possibility to create a O(1) algorithm which will output the exact number of toilet seat movements for a given period of X minutes? There are two different additional inputs:
1. The man always leaves the seat up after a visit.
2. The man always puts the seat down after a visit.
Conclusion: in the real life (which involves n being much more than m, with X->infinity), it is proven that there is no difference in a number of seat movements.
But if a man does it more often, then a woman, it will prolong the seat life if he will just leave the seat up, but is this case one of them (or both) should probably see a doctor.
Now I know what is the best for the seat itself, but which person makes more movements - is another question (which should not be asked anyways).

Yes, there is a basic O(1) algorithm.
I start with the assumption both people start "ticking" at t=0.
I believe the solution should generalize to different starting times, but it isn't hard to extend from one "free end" of the timeline to two ends.
Assume n <= m.
Then our timeline looks like this (an 'x' marks a 'move', not a visit)
0 m 2m .. t-t%m t
+-----+-----+-----+-----+-----+-----+--o
W x x x x x x x
M x x x x x x x x?
So, the woman goes floor(t/m) times, and between
each time the woman goes -- in the half-open interval (a*m,*m+m] --
the man goes at least once, thus flipping the seat once. for
each time that she flips the seat in an interval, he also flips it once.
However, he possibly will go once more after
her last trip, depending on their relative timings,
which you can calculate based on t modulo their respective periods.
total_moves = floor(t/m) * 2 + (t%m < t%n ? 1 : 0)
Now for the case n > m.
The roles of the woman and man are reversed... the half-open interval
[an, an+n) will always involve two moves. The remainder
of the line is [t-t%n, t), in which the man goes once at the beginning,
(which is +1 move, but we counted +2 for both people's moves at t=0, which we should probably discard) and the woman goes if she has equal or less time left than he does
total_moves = floor(t/n) * 2 - 1 + (t%m >= t%n ? 1 : 0)

For 2, the answer is 2*floor(X/n). The man will always go to the bathroom with the toilet seat down and leave it down. The woman will never put it down, since it's only up when the man goes to the bathroom.
1 is a little more tricky.
EDIT: Duh. For 1, the answer is 2*floor(X/m). The toilet seat only transitions when the woman goes to the bathroom.
EDIT2: Plus or minus the initial state of the toilet.
EDIT3: My answer to 1 is only correct if m>=n. I'll figure out the rest later.
EDIT4: If n>=2m, then it's 2*floor(X/n), since the seat will only transition when the man goes pee. If n>m, I believe the answer is also 2*floor(X/n), but I need to work out the math.
EDIT5: So, for 2m>n>m, the seat transitions when the man goes pee after the woman and vice versa. The sequence of man/woman visits repeats every least_common_multiple(m, n) minutes, so we only need to concern ourselves with what happens in that time period. The only time the seat would not transition when the man uses it would be if he managed to visit it twice in a row. Given that the woman is visiting more often than the man, between every man visit there is at least one woman visit. (Twice at the beginning or end.)
Answer 1 then becomes: (n>m ? 2*floor(X/n) : 2*floor(X/m)) + (remainder(X/n) > remainder(X/m) ? 1 : 0). Or something like that.

Yes there is, at least when the implementation can assume that the cycle for a man and a woman is known in advance and that it doesn't change:
Start with the least common multiple of the man/woman cycle times (lcm). Precalculate the movements for this time period (lcm_movements). Now you only have to deal with your input time modulo lcm. For this you could simply set up a fixed length table containing the number of movements for every minute.
Given that time and lcm are integers in Java/C/C++/C# the actual calculation might be this:
return ( time / lcm ) * lcm_movements + movements[ time % lcm ];

Assumptions:
we start at t=0 with the toilet seat down
if man and woman arrive at the same time, then ladies first.
Let lastLadyTime := floor(X/m)*m and lastManTime := floor(X/n)*n. They represent the last time of toilet usage. The expression (lastLadyTime > lastManTime) is the same as (X%m < X%n) because by definition X%m = X - lastLadyTime and X%n = X - lastManTime.
Case: man leaves seat down
The lady never has to move the seat but he always needs to lift it up. Hence floor(X/n).
Case: man leaves seat up, n == m
He will always need to lift it up and she will always need to push it down except at the very first toilet usage when she doesn't have to do anything. Hence 2*floor(X/n) - (X < n ? 0 : 1)
Case: man leaves seat up, n > m
Every time he uses it, he needs to lift it up. She only needs to push it down once after he uses it. This happens all the time except at the end if time runs out before she gets to use the toilet after him. Therefore we must minus 1 if lastManTime >= lastLadyTime (remember, ladies first). Hence 2*floor(X/n) - (lastManTime >= lastLadyTime ? 1 : 0) = 2*floor(X/n) - (X%n <= X%m ? 1 : 0)
Case: man leaves seat up, n < m
Similar to n > m. Every time she uses it, she needs to push it down. He only needs to lift it up once after she uses it. This happens all the time except at the end if time runs out before he has to use the toilet after her. Therefore we must minus 1 if lastManTime < lastLadyTime. Also one difference is that he needs to lift the seat the first time around. Hence 2*floor(X/m) - (lastManTime < lastLadyTime ? 1 : 0) + (X < n ? 0 : 1) = 2*floor(X/m) - (X%n > X%m ? 1 : 0) + (X < n ? 0 : 1)

If all minute variables are integers then you could do it like this:
int toilet_seat_movements = 0;
bool seat_up = false;
for (i = 0; i <= total_minutes; i++)
{
if (seat_up)
{
if (i % woman_minutes == 0)
toilet_seat_movements++;
}
else
{
if (i % man_minutes == 0)
toilet_seat_movements++;
}
}
return toilet_seat_movements;

Related

Calculate the winning strategy of a subtraction game

Problem:
Given 100 stones, two players alternate to take stones out. One can take any number from 1 to 15; however, one cannot take any number that was already taken. If in the end of the game, there is k stones left, but 1 through k have all been previously taken, one can take k stones. The one who takes the last stone wins. How can the first player always win?
My Idea
Use recursion (or dynamic programming). Base case 1, where player 1 has a winning strategy.
Reducing: for n stones left, if palyer 1 takes m1 stones, he has to ensure that for all options player 2 has (m2), he has a winning strategy. Thus the problem is reduced to (n - m1 - m2).
Follow Up Question:
If one uses DP, the potential number of tables to be filled is large (2^15), since the available options left depend on the history, which has 2^15 possibilities.
How can you optimize?
Assuming that the set of numbers remaining can be represented as R, the highest number remaining after your selection can be represented by RH and the lowest number remaining can be RL, the trick is to use your second-to-last move to raise the number to <100-RH, but >100-RH-RL. That forces your opponent to take a number that will put you in winning range.
The final range of winning, with the total number that you create with your second-to-last move, is:
N < 100-RH
N > 100-RH-RL
By observation I noted that RH can be as high as 15 and as low as 8. RL can be as low as 1 and as high as 13. From this range I evaluated the equations.
N < 100-[8:15] => N < [92:85]
N > 100-[8:15]-[1:13] => N > [92:85] - [1:13] => N > [91:72]
Other considerations can narrow this gap. RL, for instance, is only 13 in an edge circumstance that always results in a loss for Player A, so the true range is between 72 and 91. There is a similar issue with RH and the low end of it, so the final ranges and calculations are:
N < 100-[9:15] => N < [91:85]
N > 100-[9:15]-[1:12] => N > [91:85] - [1:12] => N > [90:73]
[90:73] < N < [91:85]
Before this, however, the possibilities explode. Remember, this is AFTER you choose your second-to-last number, not before. At this point they are forced to choose a number that will allow you to win.
Note that 90 is not a valid choice to win with, even though it might exist. Thus, the maximum it can be is 89. The real range of N is:
[88:73] < N < [90:85]
It is, however, possible to calculate the range of the number that you're using to put your opponent in a no-win situation. In the situation you find yourself in, the lowest number or the highest number might be the one you chose, so if RHc is the highest number you can pick and RLc is the lowest number you can pick, then
RHc = [9:15]
RLc = [1:12]
With this information, I can begin constructing a relative algorithm starting from the end of the game.
N*p* - RHp - RLp < Np < N*p* - RHp, where p = iteration and *p* = iteration + 1
RHp = [8+p:15]
RLp = [1:13-p]
p = -1 is your winning move
p = 0 is your opponent's helpless move
p = 1 is your set-up move
Np is the sum of that round.
Thus, solving the algorithm for your set-up move, p=1, you get:
N*p* - [9:15] - [1:12] < Np < N*p* - [9:15]
100 <= N*p* <= 114
I'm still working out the math for this, so expect adjustments. If you see an error, please let me know and I'll adjust appropriately.
Here is a simple, brute force Python code:
# stoneCount: number of stones to start the game with
# possibleMoves: which numbers of stones may be removed? (*sorted* list of integers)
# return value: signals if winning can be forced by first player;
# if True, the winning move is attached
def isWinningPosition(stoneCount, possibleMoves):
if stoneCount == 0:
return False
if len(possibleMoves) == 0:
raise ValueError("no moves left")
if stoneCount in possibleMoves or stoneCount < possibleMoves[0]:
return True,stoneCount
for move in possibleMoves:
if move > stoneCount:
break
remainingMoves = [m for m in possibleMoves if m != move]
winning = isWinningPosition(stoneCount - move, remainingMoves)
if winning == False:
return True,move
return False
For the given problem size this function returns in less than 20 seconds on an Intel i7:
>>> isWinningPosition(100, range(1,16))
False
(So the first play cannot force a win in this situation. Whatever move he makes, it will result in a winning position for the second player.)
Of course, there is a lot of room for run time optimization. In the above implementation many situations are reached and recomputed again and again (e.g. when the first play takes one stone and the second player takes two stones this will put the first player into the same situation as when the number of stones taken by each player are reversed). So the first (major) improvement is to memorize already computed situations. Then one could go for more efficient data structures (e.g. encoding the list of possible moves as bit pattern).

How do I solve this dynamic programming?

I am practising DP and I came across this question. http://www.spoj.com/problems/MPILOT/en/
Charlie acquired airline transport company and to stay in business he needs to lower the expenses by any means possible. There are N pilots working for his company (N is even) and N/2 plane crews needs to be made. A plane crew consists of two pilots - a captain and his assistant. A captain must be older than his assistant. Each pilot has a contract granting him two possible salaries - one as a captain and the other as an assistant. A captain's salary is larger than assistant's for the same pilot. However, it is possible that an assistant has larger salary than his captain. Write a program that will compute the minimal amount of money Charlie needs to give for the pilots' salaries if he decides to spend some time to make the optimal (i.e. the cheapest) arrangement of pilots in crews.
Input
The first line of input contains integer N, 2 ≤ N ≤ 10,000, N is even, the number of pilots working for the Charlie's company. The next N lines of input contain pilots' salaries. The lines are sorted by pilot's age, the salaries of the youngest pilot are given the first. Each of those N lines contains two integers separated by a space character, X i Y, 1 ≤ Y < X ≤ 100,000, a salary as a captain (X) and a salary as an assistant (Y).
Output
The first and only line of output should contain the minimal amount of money Charlie needs to give for the pilots' salaries.
After research, I found out this will be solved by DP but how exactly do I solve this? I have spent hours reading up on the links but I didn't get one which is easily understandable. Please help me.
There's actually a nice way to visualize it. Starting from the bottom left, the start of our ascending list, we can envision choosing a Y (assistant's salary) as a movement to the right and an X (captain's salary) as a movement up, with the condition that the southwest-northeast diagonal is not crossed (see Catalan Number in Wikipedia).
From this we can see that each node in the triangle has at most two predecessors, from the west or from the south, and so the bottom-up general case ought to be:
captain assistant
dp[i][j] = min(x[i+j-1] + dp[i-1][j], y[i+j-1] + dp[i][j-1])
Example:
x = [4,5,6,7]
y = [3,2,1,2]
[9+7]
[3+5] [min(8+1,5+6)]
[.] [3] [3+2]
I'll leave coding as an exercise.
As usual, we need to find a compact set of subproblems. Remembering the details of how the pilots are matched won't do -- we need something like the following characterization.
Consider a labeling that makes each pilot a captain or an assistant without regard to matching. There exists a valid matching if and only if the following two conditions hold:
There are N/2 captains and N/2 assistants.
For every age cutoff, there are at least as many assistants who are younger than the cutoff as there are captains who are younger than the cutoff.
The "only if" direction is easy: Condition 1 is obvious, and Condition 2 holds because the inequality holds for each 2-pilot crew, and we can sum the inequalities.
For the "if" direction, we actually have to construct crews. We proceed by induction. If there are no pilots, then the empty match is valid. Otherwise, since the youngest pilot is an assistant (by Condition 2) and there exists at least one captain (by Condition 1), there exists (by Sperner's lemma if you want to get fancy) a pair of pilots such that (a) no pilots are intermediate in age (b) the younger of the pair is an assistant (c) the older of the pair is a captain. Match the pair and remove them from the pool. Observe that both Conditions still hold, so match the rest by inductive hypothesis.
This observation leads to an O(N^2)-time dynamic program. We repeatedly read the salaries of the next oldest pilot and then compute, given that K pilots have been considered so far, for all C from 0 to [K/2], the minimum cost of paying K - C assistants and C captains among these pilots. At the end, return the cost of paying N/2 assistants and N/2 captains. Untested Python:
def cost(pilots):
cost = [0]
for i, (assistant_salary, captain_salary) in enumerate(pilots):
cost.append(float('inf')) # two-way sentinel
cost = [min(cost[c] + assistant_salary,
cost[c - 1] + captain_salary)
for c in range((i + 1) / 2 + 1)]
return cost[-1] # i.e., N/2
Let's formulate some conditions for a recursion: if we've reached the end, return the sum; if we have N/2 assistants, add a captain next; if we have the same number of assistants as captains left, add an assistant next (we can't have a captain younger than an assistant); otherwise, return the minimum cost of either adding a captain or an assistant.
JavaScript code:
var x = [4,5,6,7];
var y = [3,2,1,2];
var n = x.length;
function f(i,ys,s){
if (i == n){
return s;
}
if (ys == n / 2){
return f(i + 1,ys,s + x[i]);
} else if (i % 2 == 0 && ys == i / 2){
return f(i + 1,ys + 1,s + y[i]);
} else {
return Math.min(f(i + 1,ys + 1,s + y[i]),f(i + 1,ys,s + x[i]));
}
}
Output:
console.log(f(0,0,0)) // 16
For recursive approach in c++, you can follow this code for better understanding:
int min_salary(int a[],int n,int x,int c[])
{
if(n==0)
return 0;
if(x==0)
return(a[0]+min_salary(a+1,n-1,1,c+1));
if(x==n)
return(c[0]+min_salary(a+1,n-1,x-1,c+1));
else
return(min(a[0]+min_salary(a+1,n-1,x+1,c+1),c[0]+min_salary(a+1,n-1,x-1,c+1)));
}

How to efficiently detect a tie early in m,n,k-game (generalized tic-tac-toe)?

I'm implementing an m,n,k-game, a generalized version of tic-tac-toe, where m is the number of rows, n is the number of columns and k is the number of pieces that a player needs to put in a row to win. I have implemented a check for a win, but I haven't figured out a satisfactory way to check before the board is full of pieces, if no player can win the game. In other words, there might be empty slots on the board, but they cannot be filled in such a way that one player would win.
My question is, how to check this efficiently? The following algorithm is the best that I can think of. It checks for two conditions:
A. Go over all board positions in all 4 directions (top to bottom, right to left, and both diagonal directions). If say k = 5, and 4 (= k-1) consecutive empty slots are found, stop checking and report "no tie". This doesn't take into account for example the following situation:
OX----XO (Example 1)
where a) there are 4 empty consecutive slots (-) somewhere between two X's, b) next it is O's turn, c) there are less than four other empty positions on the board and no player can win by putting pieces to those, and d) it is not possible to win in any other direction than horizontally in the shown slots either. Now we know that it is a tie because O will eventually block the last winning possibility, but erroneously it is not reported yet because there are four consecutive empty slots. That would be ok (but not great). Checking this condition gives a good speed-up at the beginning when the checking algorithm usually finds such a case early, but it gets slower as more pieces are put on the board.
B. If this k-1-consecutive-empty-slots-condition isn't met, the algorithm would check the slots again consecutively in all 4 directions. Suppose we are currently checking from left to right. If at some point an X is encountered and it was preceded by an O or - (empty slot) or a board border, then start counting the number of consecutive X's and empty slots, counting in this first encountered X. If one can count to 5, then one knows it is possible for X to win, and "no tie" is reported. If an O preceded by an X is encountered before 5 consecutive X's, then X cannot win in those 5 slots from left to right starting from where we started counting. For example:
X-XXO (Example 2)
12345
Here we started checking at position 1, counted to 4, and encountered an O. In this case, one would continue from the encountered O in the same way, trying to find 5 consecutive O's or empty slots this time. In another case when counting X's or empty slots, an O preceded by one or more empty slots is encountered, before counting to 5. For example:
X-X-O (Example 3)
12345
In this case we would again continue from the O at position 5, but add to the new counter (of consecutive O's or empty slots) the number of consecutive empty slots that preceded O, here 1, so that we wouldn't miss for example this possible winning position:
X-X-O---X (Example 4)
In this way, in the worst case, one would have to go through all positions 4 times (4 directions, and of course diagonals whose length is less than k can be skipped), giving running time O(mn).
The best way I could think of was doing these two described checks, A and B, in one pass. If the checking algorithm gets through all positions in all directions without reporting "no tie", it reports a tie.
Knowing that you can check a win just by checking in the vicinity of the last piece that was added with running time O(k), I was wondering if there were quicker ways to do an early check for a tie. Doesn't have to be asymptotically quicker. I'm currently keeping the pieces in a two-dimensional array. Is there maybe a data structure that would allow an efficient check? One approach: what is the highest threshold of moves that one can wait the players to make before running any checks for a tie at all?
There are many related questions at Stack Overflow, for example this, but all discussions I could find either only pointed out the obvious tie condition, where the number of moves made is equal to the size of the board (or they checked if the board is full), or handled only the special case where the board is square: m = n. For example this answer claims to do the check for a tie in constant time, but only works when m = n = k. I'm interested in reporting the tie as early as possible and for general m,n and k. Also if the algorithm works for more than two players, that would be neat.
I would reduce the problem of determining a tie to the easier sub-problem:
Can player X still win?
If the answer is 'no' for all players, it is a tie.
To find out whether Player X can win:
fill all blank spaces with virtual 'X'-pieces
are there k 'X'-pieces in a row anywhere?
if there are not --> Player X cannot win. return false.
if there are, find the row of k stones with the least amount of virtual pieces. Count the number of virtual pieces in it.
count the number of moves player X has left, alternating with all other players, until the board is completely full.
if the number of moves is less than the amount of virtual pieces required to win, player X cannot win. return false.
otherwise, player X can still win. return true.
(This algorithm will report a possible win for player X even in cases where the only winning moves for X would have another player win first, but that is ok, since that would not be a tie either)
If, as you said, you can check a win just by checking in the vicinity of the last piece that was added with running time O(k), then I think you can run the above algorithm in O(k * Number_of_empty_spots): Add all virtual X-Piece, note any winning combinations in the vicinity of the added pieces.
The number of empty slots can be large, but as long as there is at least one empty row of size k and player X has still k moves left until the board is filled, you can be sure that player X can still win, so you do not need to run the full check.
This should work with any number of players.
Actually the constant time solution you referenced only works when k = m = n as well. If k is smaller then I don't see any way to adapt the solution to get constant time, basically because there are multiple locations on each row/column/diagonal where a winning consecutive k 0's or 1's may occur.
However, maintaining auxiliary information for each row/column/diagonal can give a speed up. For each row/column/diagonal, you can store the start and end locations for consecutive occurrences of 1's and blanks as possible winning positions for player 1, and similarly store start and end locations of consecutive occurrences of 0's and blanks as possible winning positions for player 0. Note that for a given row/column/diagonal, intervals for player 0 and 1 may overlap if they contain blanks. For each row/column/diagonal, store the intervals for player 1 in sorted order in a self-balancing binary tree (Note you can do this because the intervals are disjoint). Similarly store the intervals for player 0 sorted in a tree. When a player makes a move, find the row/column/diagonals that contain the move location and update the intervals containing the move in the appropriate row column and diagonal trees for the player that did not make the move. For the player that did not make a move, this will split an interval (if it exists) into smaller intervals that you can replace the old interval with and then rebalance the tree. If an interval ever gets to length less than k you can delete it. If a tree ever becomes empty then it is impossible for that player to win in that row/column/diagonal. You can maintain a counter of how many rows/columns/diagonals are impossible to win for each player, and if the counter ever reaches the total number of rows/columns/diagonals for both players then you know you have a tie. The total running time for this is O(log(n/k) + log(m/k)) to check for a tie per move, with O(mn/k) extra space.
You can similarly maintain trees that store consecutive intervals of 1's (without spaces) and update the trees in O(log n + log m) time when a move is made, basically searching for the positions before and after the move in your tree and updating the interval(s) found and merging two intervals if two intervals (before and after) are found. Then you report a win if an interval is ever created/updated and obtains length greater than or equal to k. Similarly for player 0. Total time to check for a win is O(log n + log m) which may be better than O(k) depending on how large k is. Extra space is O(mn).
Let's look at one row (or column or diagonal, it doesn't matter) and count the number of winning lines of length k ("k-line") it's possible to make, at each place in the row, for player X. This solution will keep track of that number over the course of the game, checking fulfillment of the winning condition on each move as well as detecting a tie.
1 2 3... k k k k... 3 2 1
There is one k-line including an X in the leftmost slot, two with the second slot from the left, and so on. If an opposing player, O or otherwise, plays in this row, we can reduce the k-line possibility counts for player X in O(k) time at the time of the move. (The logic for this step should be straightforward after doing an example, needing no other data structure, but any method involving checking each of the k rows of k from will do. Going left to right, only k operations on the counts is needed.) An enemy piece should set the possibility count to -1.
Then, a detectably tied game is one where no cell has a non-zero k-line possibility count for any player. It's easy to check this by keeping track of the index of the first non-zero cell. Maintaining the structure amounts to O(k*players) work on each move. The number of empty slots is less than those filled, for positions that might be tied, so the other answers are good for checking a position in isolation. However, at least for reasonably small numbers of players, this problem is intimately linked with checking the winning condition in the first place, which at minimum you must do, O(k), on every move. Depending on your game engine there may be a better structure that is rich enough to find good moves as well as detect ties. But the possibility counting structure has the nice property that you can check for a win whilst updating it.
If space isn't an issue, I had this idea:
For each player maintain a structure sized (2mn + (1 - k)(m + n) + 2(m - k + 1)(n - k + 1) + 2(sum 1 to (m - k))) where each value represents if one of another player's moves are in one distinct k-sized interval. For example for a 8-8-4 game, one element in the structure could represent row 1, cell 0 to 3; another row 1, cell 1 to 4; etc.
In addition, one variable per player will represent how many elements in their structure are still unset. Only one move is required to set an element, showing that that k-interval can no longer be used to win.
An update of between O(k) and O(4k) time per player seems needed per move. A tie is detected when the number of players exceeds the number of different elements unset.
Using bitsets, the number of bytes needed for each player's structure would be the structure size divided by 8. Notice that when k=m=n, the structure size is 4*k and update time O(4). Less than half a megabyte per player would be needed for a 1000,1000,5 game.
Below is a JavaScript example.
var m = 1000, n = 1000, k = 5, numberOfPlayers = 2
, numberOfHorizontalKIs = m * Math.max(n - k + 1,0)
, numberOfverticalKIs = n * Math.max(m - k + 1,0)
, horizontalVerticalKIArraySize = Math.ceil((numberOfHorizontalKIs + numberOfverticalKIs)/31)
, horizontalAndVerticalKIs = Array(horizontalVerticalKIArraySize)
, numberOfUnsetKIs = horizontalAndVerticalKIs
, upToM = Math.max(0,m - k) // southwest diagonals up to position m
, upToMSum = upToM * (upToM + 1) / 2
, numberOfSouthwestKIs = 2 * upToMSum //sum is multiplied by 2 to account for bottom-right-corner diagonals
+ Math.max(0,n - m + 1) * (m - k + 1)
, diagonalKIArraySize = Math.ceil(2 * numberOfSouthwestKIs/31)
, diagonalKIs = Array(diagonalKIArraySize)
, numberOfUnsetKIs = 2 * numberOfSouthwestKIs + numberOfHorizontalKIs + numberOfverticalKIs
function checkTie(move){
var row = move[0], column = move[1]
//horizontal and vertical
for (var rotate=0; rotate<2; rotate++){
var offset = Math.max(k - n + column, 0)
column -= offset
var index = rotate * numberOfHorizontalKIs + (n - k + 1) * row + column
, count = 0
while (column >= 0 && count < k - offset){
var KIArrayIndex = Math.floor(index / 31)
, bitToSet = 1 << index % 31
if (!(horizontalAndVerticalKIs[KIArrayIndex] & bitToSet)){
horizontalAndVerticalKIs[KIArrayIndex] |= bitToSet
numberOfUnsetKIs--
}
index--
column--
count++
}
//rotate board to log vertical KIs
var mTmp = m
m = n
n = mTmp
row = move[1]
column = move[0]
count = 0
}
//rotate board back
mTmp = m
m = n
n = mTmp
// diagonals
for (var rotate=0; rotate<2; rotate++){
var diagonalTopColumn = column + row
if (diagonalTopColumn < k - 1 || diagonalTopColumn >= n + m - k){
continue
} else {
var offset = Math.max(k - m + row, 0)
row -= offset
column += offset
var dBeforeM = Math.min (diagonalTopColumn - k + 1,m - k)
, dAfterM = n + m - k - diagonalTopColumn
, index = dBeforeM * (dBeforeM + 1) / 2
+ (m - k + 1) * Math.max (Math.min(diagonalTopColumn,n) - m + 1,0)
+ (diagonalTopColumn < n ? 0 : upToMSum - dAfterM * (dAfterM + 1) / 2)
+ (diagonalTopColumn < n ? row : n - 1 - column)
+ rotate * numberOfSouthwestKIs
, count = 0
while (row >= 0 && column < n && count < k - offset){
var KIArrayIndex = Math.floor(index / 31)
, bitToSet = 1 << index % 31
if (!(diagonalKIs[KIArrayIndex] & bitToSet)){
diagonalKIs[KIArrayIndex] |= bitToSet
numberOfUnsetKIs--
}
index--
row--
column++
count++
}
}
//mirror board
column = n - 1 - column
}
if (numberOfUnsetKIs < 1){
return "This player cannot win."
} else {
return "No tie."
}
}

Three egg proble​m

I was just reading The Two Egg Problem:
The Two Egg Problem
You are given two eggs, and access to a 100-storey building. Both eggs are identical. The aim is to find out the highest floor from which an egg will not break when dropped out of a window from that floor. If an egg is dropped and does not break, it is undamaged and can be dropped again. However, once an egg is broken, that’s it for that egg.
If an egg breaks when dropped from floor n, then it would also have broken from any floor above that. If an egg survives a fall, then it will survive any fall shorter than that.
The question is: What strategy should you adopt to minimize the number egg drops it takes to find the solution?. (And what is the worst case for the number of drops it will take?)
I was following along until the "Look see I can do three" section. The author states that after the first egg breaks it degrades into the 2-egg problem and can be solved recursively.
That's great, but wouldn't we want to choose larger step-sizes when using 3 eggs instead of 2 (for the first egg)? From which floor do we throw the first egg?
With 1 egg, we have to start at floor 1.
With 2 eggs, we solve for n(n+1)/2=k and round up, where n is the starting floor, and k is the number of floors.
With 3... I'm having trouble coming up with a formula.
Thinking about this a bit more, with 2 eggs, the maximum number of drops is equal to the floor number that we drop our first egg from. For example, with 2 eggs and 100 floors, the solution is 14, which means we drop the first egg from floor 14, and if it breaks, we have to drop up to 13 more times, for floors 1-13.
With 3 eggs, the solution is 9 (as shown in the chart). But we wouldn't want to throw the first egg at floor 9, we can throw it higher, because we don't have to iterate by 1s in-between.
If we throw from floor 14 again, and it breaks, then we recurse. n(n+1)/2=k where k is now 13... but that gives us 4.815, if we ceil and that and add our previous drop we get 6, which is lower than the actual solution, so something here is wrong...
If we throw from floor 14 again, and it breaks, then we recurse. n(n+1)/2=k where k is now 13... but that gives us 4.815, if we ceil and that and add our previous drop we get 6, which is lower than the actual solution, so something here is wrong...
What if it doesn't break? Then you have a three-egg problem with 86 floors, which takes maybe one drop less to solve than the 100-floor problem.
Say you drop the first egg from the 50th floor. If it breaks, you have a two-egg problem with 49 floors, which takes up to 10 additional drops. So that would give you a worst-case of 11 drops (since if it doesn't break, the 50-floor three-egg problem takes at most 7 additional drops).
If you choose the 37th floor for the first drop, if it breaks, you have a 36-floor two-egg problem, needing up to 8 additional drops. If it doesn't break, you have a 63-floor three-egg problem left. You want to solve that problem with at most 8 drops, so if the next drop breaks the egg, the remaining two-egg problem should be solvable in at most 7 drops, thus the highest floor you can choose for the second drop is 37 + 28 + 1 = 66, since 28 floors is the highest you can solve with at most 7 drops and two eggs. If the egg doesn't break, you have a 34-floor three-egg problem with 7 drops left. The highest you can certainly solve with the remaining 6 drops if the egg breaks is 21 (6*7/2), so you can choose floor 66 + 21 + 1 = 88. If the egg doesn't break, you have 12 floors left with 6 drops, which is already doable with only two eggs.
Systematically, the highest number of floors you can certainly solve with d drops and e eggs is
/ 1, if d == 1
F(e,d) = | d, if e == 1
\ F(e-1,d-1) + 1 + F(e,d-1), if e > 1 and d > 1
If you have only one drop, you have no choice but to choose the lowest floor of which you do not yet know that the egg doesn't break. If that breaks it, and you tried a higher floor, you don't know the first floor to break the egg.
If you have only one egg, you have to check every floor in order until the egg breaks or you run out of drops.
Otherwise, if the first drop is from a floor higher than F(e-1,d-1) + 1, you possibly can't find the first breaking floor if the egg breaks. If the first drop is from a lower floor, you can't reach as high with d-1 drops if the egg doesn't break, so the first drop should be from floor F(e-1,d-1) + 1. If it breaks, you can solve with the remaining e-1 eggs and d-1 drops by assumption. If not, you can solve for the next F(e,d-1) floors with the remaining drops and eggs.
Conversely, to find how many drops you may need for f floors with e eggs, you have to find
D(e,f) = min { d | F(e,d) >= f }
You can find that by calculating the F(e,d) matrix, or you can use dynamic programming:
If you choose floor s for the first drop, if the egg breaks, you need up to D(e-1,s-1) drops to determine the floor. If the egg doesn't break, you need up to D(e,f-s) drops to determine the floor.
So the worst case for choosing floor s for the first drop is
WC(s,e,f) = 1 + max { D(e-1,s-1), D(e,f-s) }
and the best of the worst case is
D(e,f) = minimum { WC(s,e,f) | 1 <= s <= f }
(where of course D(e,0) = 0).
This problem can be solved with following 3 approaches (that I know) :
Dynamic Programming
Solution using Binary Search Tree
Solution by obtaining the direct mathematical formula for maximum number of floors that can be tested or covered with given number of eggs and given number of drops
Let me first define some symbols as follows:
e = number of eggs
f = number of floors in building
n = number of egg drops
Fmax(e, n) = maximum number of floors that can be tested with e eggs and n drops
The crux for dynamic programming approach lies in following recursive formula for Fmax:
Fmax(e, n) = 1 + Fmax(e-1, n-1) + fmax(e, n-1)
And the crux for obtaining the direct mathematical formula for Fmax lies in following recursive formula for Fmax:
Fmax(e, n) = { ∑Fmax(e-1,i) for i = 1 to n } - Fmax(e-1, n) + n
Alternative solution using Binary Search Tree (BST) is also possible for this problem. In order to facilitate our analysis, let us draw BST with slight modifications as follows:
1. If egg breaks then child node is drawn on left down side
2. If egg does not break then child node is drawn straight down side
If we draw BST with above kind of representation then width of the BST (i.e. number of vertical columns in BST) represents the number of eggs.
Any BST with f number of nodes, drawn with above kind of representation and subjected to the constraint width of BST <= e (number of eggs) is a solution but it may not be the optimal solution.
Hence obtaining the optimal solution is equivalent to obtaining the arrangement of nodes in BST with minimum height subjected to the constraint: width of BST <= e
For more details about all the above 3 approaches, check my blog at: 3 approaches for solving generalized egg drop problem
This is the same answer that I provided at Egg Drop Printing Solutions. I am providing it here for anyone who wants to see the whole decision tree and reasoning laid out.
# This uses dynamic programming to find the basic information.
def optimal_solution(floors, eggs):
# dp[drops][eggs] = max_floors
dp = []
# With no drops, we can do no floors
dp.append([0 for x in range(eggs+1)])
# With one drop and any eggs, we can do 1 floor
one_drop = [1 for _ in range(eggs+1)]
one_drop[0] = 0 # Except no eggs is still no floors
dp.append(one_drop)
# Keep adding drops until we have our answer
# Note, in python array element -1 is shorthand for the end of the array.
while dp[-1][eggs] < floors:
# 0 floors for 0 eggs. 1 more for one egg
next_drop = [0, dp[-1][1] + 1]
for i in range(2, eggs+1): # Python for 2..eggs
# The best we can do is drop at floor dp[-1][i-1].
# If the egg breaks, we can find the answer using that solution.
# If the egg holds, we can find another dp[-1][i] floors.
next_drop.append(dp[-1][i] + dp[-1][i-1])
dp.append(next_drop)
return dp
# This turns that optimal solution into a decision tree.
def dp_to_decision_tree(dp, floors, start_floor=None, eggs=None, drops=None):
# Figure out defaults if needed.
if start_floor is None:
start_floor = 0
if drops is None:
drops = len(dp) - 1
if eggs is None:
eggs = len(dp[0]) - 1
# Are we done?
if floors == start_floor:
return start_floor
elif dp[drops][eggs] < floors - start_floor:
return None
# Do we need all of our drops?
while floors - start_floor < dp[drops-1][eggs]:
drops -= 1
drop_at = start_floor + dp[drops-1][eggs-1]
if eggs == 1:
drop_at = start_floor + 1
if floors < drop_at:
drop_at = floors
return [
drop_at,
dp_to_decision_tree(dp, floors, drop_at, eggs, drops-1),
dp_to_decision_tree(dp, drop_at-1, start_floor, eggs-1, drops-1),
{'eggs': eggs, 'floor_range': (start_floor, floors)}
]
# This prints the decision tree in a human readable format.
def print_decision_tree(tree, indent="", label="start"):
if tree is None:
print(f"{indent}{label}: ?")
elif isinstance(tree, int):
print(f"{indent}{label}: {tree} found")
else:
print(f"{indent}{label}: {tree[0]} {tree[3]}")
print_decision_tree(tree[1], indent + " ", label="held")
print_decision_tree(tree[2], indent + " ", label="broke")
# And this calls the previous functions.
def print_optimal_decisions(floors, eggs):
print_decision_tree(
dp_to_decision_tree(
optimal_solution(floors, eggs), floors))
# And now we can try it.
print_optimal_decisions(36, 3)
You can use simple dynamic programming solution.
n - number of floors.
k - number of eggs.
D[n,k] = you answer (The number of minimum throws).
D[j,1] = n-1 for each 1 <= j <= n.
The main idea for calculate D[n,k] for k>1:
D[n,k] = maximum 1 <= j <= n-1 { maximum{ D[j,k-1]+1, D[n-j,k]+1 }.
The blog here explains the mathematical approach for 3 eggs with 1000 floors:
https://sankalpiitr.wordpress.com/2012/03/02/the-2-eggs-problem-extended-to-3-eggs/
According to this blog formula would be
P = N + ( N * ( N + 1 ) * ( N – 1 ) ) /6
where P is the number of floors and N is the minimum drops required.
So solving for P=100, we get N as 8.2

Who owes who money optimization

Say you have n people, each who owe each other money. In general it should be possible to reduce the amount of transactions that need to take place. i.e. if X owes Y £4 and Y owes X £8, then Y only needs to pay X £4 (1 transaction instead of 2).
This becomes harder when X owes Y, but Y owes Z who owes X as well. I can see that you can easily calculate one particular cycle. It helps for me when I think of it as a fully connected graph, with the edges being the amount each person owes.
Problem seems to be NP-complete, but what kind of optimisation algorithm could I make, nevertheless, to reduce the total amount of transactions? Doesn't have to be that efficient, as N is quite small for me.
Edit:
The purpose of this problem would be to be able to have in the accounting system something that can say to each person when they log in "You can remove M amount of transactions by simply paying someone X amount, and someone else Y amount". Hence the bank solution (though optimal if everyone is paying at the same time) cannot really be used here.
Are people required to clear their debts by paying somebody that they actually owe money to personally? If not, the following seems to work suspiciously easily:
For each person, work out the net amount they should pay, or should receive.
Have somebody who owes money net pay somebody who should receive money net min(amount owed, amount to be received). After this, at least one of the two participants owes nothing and should receive nothing, and so can be removed from the problem.
Assuming I have missed something, what are the constraints that apply (or gross error made)?
I have created an Android app which solves this problem. You can input expenses during the trip, it even recommends you "who should pay next". At the end it calculates "who should send how much to whom". My algorithm calculates minimum required number of transactions and you can setup "transaction tolerance" which can reduce transactions even further (you don't care about $1 transactions) Try it out, it's called Settle Up:
https://market.android.com/details?id=cz.destil.settleup
Description of my algorithm:
I have basic algorithm which solves the problem with n-1 transactions, but it's not optimal. It works like this: From payments, I compute balance for each member. Balance is what he paid minus what he should pay. I sort members according to balance increasingly. Then I always take the poorest and richest and transaction is made. At least one of them ends up with zero balance and is excluded from further calculations. With this, number of transactions cannot be worse than n-1. It also minimizes amount of money in transactions. But it's not optimal, because it doesn't detect subgroups which can settle up internally.
Finding subgroups which can settle up internally is hard. I solve it by generating all combinations of members and checking if sum of balances in subgroup equals zero. I start with 2-pairs, then 3-pairs ... (n-1)pairs. Implementations of combination generators are available. When I find a subgroup, I calculate transactions in the subgroup using basic algorithm described above. For every found subgroup, one transaction is spared.
The solution is optimal, but complexity increases to O(n!). This looks terrible but the trick is there will be just small number of members in reality. I have tested it on Nexus One (1 Ghz procesor) and the results are: until 10 members: <100 ms, 15 members: 1 s, 18 members: 8 s, 20 members: 55 s. So until 18 members the execution time is fine. Workaround for >15 members can be to use just the basic algorithm (it's fast and correct, but not optimal).
Source code:
Source code is available inside a report about algorithm written in Czech. Source code is at the end and it's in English:
http://settleup.destil.cz/report.pdf
Nominate one person arbitrarily to be the banker.
Each other person transfers the sum of all the outgoing transactions minus the incoming transactions (so either deposits or withdraws) to that person.
There will be a maximum of (n-1) transactions, which is pretty small. It is fast. It is simple.
Given that everyone who transfers money will have to be involved in a transaction anyway*, it is bounded to be at worst twice the optimal case.**
* The exception is the banker themselves. A quick optimisation is to ensure the nominated banker is not someone who holds a neutral position.
** Explaining my upper bound logic further:
Suppose the optimal case is A gives $1 to B, and C gives $1 to D, and E is neutral = two transactions.
Then with this logic, if E is the nominated banker, A gives $1 to E, E gives $1 to B, C gives $1 to E and E gives $1 to D = four transactions.
With the optimisation, making sure you don't choose a neutral person for banker, select A instead.
A gives $1 to B, C gives $1 to A. A gives $1 to D = three transactions.
for each debt in debts
debt.creditor.owed -= debt.amount
debt.deptor.owed += debt.amount
end
for each person in persons
if person.owed > 0 then
deptors.add person
else if person.owed < 0 then
creditors.add person
end
end
deptors.sort_by_owed_desc
creditor.sort_by_owed_asc
for each debtor in deptors
while debtor.owed > 0
creditor = creditors.top
amount = min( debtor.owed, -creditor.owed)
creditor.owed += amount
debtor.owed -= amount
if creditor.owed == 0 then
creditors.remove_top
end
write debtor.name " owes " creditor.name " " amount "€"
end
end
Just thinking about it I'd start by looking at each cycle in the directed graph and reducing each edge in the cycle by the value of the minimum edge in the cycle, then remove the minimum edge altogether. Rinse and repeat.
Here's the Python solution I used; it's the same idea as Gunner's post, with a few line changes:
for i in N:
for j in N:
if i!=j and owes[i][j] > owes[j][i]:
owes[i][j] -= owes[j][i]
owes[j][i] = 0
for k in N:
for i in N:
for j in N:
if k == i or i == j or k == j:
continue
if owes[j][k] > owes[i][j]:
owes[i][k] += owes[i][j]
owes[j][k] -= owes[i][j]
owes[i][j] = 0;
Works a treat.
You can test it with i.e.:
owes = [[0,2,11], [4,0,7], [2,3,0]]
N = range(len(owes))
I think you need to build a different data structure ( a tree, each time one person is the root node) that will check for each person how many "transaction" can you "kill", than, choose the best one, make the cycle, and rebuild it again.it is not o(N), I Think it's N^2 though, and it will not give you the best result. it is just a strategy.
This problem may be tackled with the Warshall algorithm.
for(i=0;i<n;i++)
for(j=0;j<n;j++)
if ( i!= j && owes[i][j] > owes[j][i] )
owes[i][j] -= (owes[i][j] - owes[j][i]), owes[j][i] = 0;
for(k=0;k<n;k++)
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
if( k == i || i == j || k == j ) continue;
if ( owes[j][k] > owes[i][j] )
{
int diff = owes[j][k] - owes[i][j];
owes[i][j] = 0;
owes[i][k ] += diff;
owes[j][k] -= diff;
}
}
After the algorithm finishes, the total number of transactions required would be the number of positive entries in the owes table.
I have not verified yet whether the algorithm will work, based on nature of the problem it may work. Solution is O(N^3).
I think you must remove all cicles reducing edges by minimal edge value and removingedges with value 0. After it you will get graph withouth cicles. I think you must find vertexes, wich have no pointers to them (man's wich owes only others money). This man's must pay money, beacouse there is no one to pay the money for them. So my point is that you must find somehow who they must pay.
I have a solution to the problem written in matlab. It is based on a matrix of who owes who what. The number in the (i,j) means that person j owes person i the number. E.g.
B owes A 2
and A owes B 1
of course in this case it is trivial that B should just give A 1
This becomes more complex with more entries. However, with the algorithm i wrote i can guarantee that no more than N-1 transactions occurs where N is the number of persones 2 in this case.
Here is the code i wrote.
function out = whooweswho(matrix)
%input sanitation
if ~isposintscalar(matrix)
[N M] = size(matrix);
if N ~= M
error('Matrix must be square');
end
for i=1:N
if matrix(N,N) ~= 0
error('Matrix must have zero on diagonals');
end
end
else
%construction of example matrix if input is a positive scalar
disp('scalar input: Showing example of NxN matrix randomly filled');
N = matrix;
matrix = round(10*N*rand(N,N)).*(ones(N,N)-eye(N))
end
%construction of vector containing each persons balance
net = zeros(N,1);
for i=1:N
net(i) = sum(matrix(i,:))-sum(matrix(:,i));
end
%zero matrix, so it can be used for the result
matrix = zeros(size(matrix));
%sum(net) == 0 always as no money dissappears. So if min(net) == 0 it
%implies that all balances are zero and we are done.
while min(net) ~= 0
%find the poorest and the richest.
[rec_amount reciever] = max(net);
[give_amount giver] = min(net);
%balance so at least one of them gets zero balance.
amount =min(abs(rec_amount),abs(give_amount));
net(reciever) = net(reciever) - amount;
net(giver) = net(giver) + amount;
%store result in matrix.
matrix(reciever,giver) = amount;
end
%output equivalent matrix of input just reduced.
out = matrix;
end

Resources