Count number of unique node sequences producing the same BST - algorithm

The problem:
Given a particular sequence of up to 50 integers, which represent
nodes of a certain binary search tree (BST), how many permutations of
this sequence are there, which will also give rise to exactly the same
BST? Include the original sequence in your total count as 1 sequence.
For instance, answer = 6 for such a sequence [5,2,1,9,8]: [5,2,1,9,8]
(itself, the original sequence given), [5,9,8,2,1], [5,2,9,1,8],
[5,9,2,1,8], [5,2,9,8,1], [5,9,2,8,1]

Suppose you have your example sequence [5,2,1,9,8]. The first node will become the root of the binary tree, so we know the first node must be 5.
From then on, all the nodes smaller than 5 will go to the left child, and all the nodes greater than 5 will go to the right child.
So you can solve this recursively, count the number of ways of making the left subtree (consisting of [2,1]) multiply by the number of ways of making the right subtree (consisting of [9,8]) and multiply by the number of ways of ordering the arrival of integers on opposite sides.
Sample code
def nCr(n,r):
"""Return number of ways of choosing r objects from n"""
top, bottom = 1, 1
for i in xrange(r):
top *= n
n = n - 1
bottom *= r
r = r- 1
return top / bottom
def count_ways_to_make_bst(seq):
if len(seq)<=1:
return 1
num_remaining = len(seq) - 1
left = [r for r in seq[1:] if r>seq[0]]
right = [r for r in seq[1:] if r<seq[0]]
return count_ways_to_make_bst(left) * count_ways_to_make_bst(right) * nCr(num_remaining,len(left))

Assume that the given node sequence is the order in which we added those elements into the BST.
We can easily see that if two nodes a and b belong to two different branches, so the order of adding a and b will not affect the final structure.
We only need to ensure that the parent need to be added first, before its children is added.
For the example [5,2,1,9,8]: 5 should always added first.
There will be only two choices: add 2 or add 9
If we add 2: 1 can be added in any order
similarly, If we add 9: 8 can be added anytime after that
So, now we have our algo while travelling from root -> leaf:
int numberOfWays (Node node) {
if(node is leaf) return 1;
int a = numberOfWays(node.left);
int b = numberOfWays(node.right);
int x = number of node in the left;
int y = number of node in the right;
//nCr is combination, so we can choose x places in total of x + y positions
return nCr(x+y,x) * a * b;
}

Related

How to adapt Fenwick tree to answer range minimum queries

Fenwick tree is a data-structure that gives an efficient way to answer to main queries:
add an element to a particular index of an array update(index, value)
find sum of elements from 1 to N find(n)
both operations are done in O(log(n)) time and I understand the logic and implementation. It is not hard to implement a bunch of other operations like find a sum from N to M.
I wanted to understand how to adapt Fenwick tree for RMQ. It is obvious to change Fenwick tree for first two operations. But I am failing to figure out how to find minimum on the range from N to M.
After searching for solutions majority of people think that this is not possible and a small minority claims that it actually can be done (approach1, approach2).
The first approach (written in Russian, based on my google translate has 0 explanation and only two functions) relies on three arrays (initial, left and right) upon my testing was not working correctly for all possible test cases.
The second approach requires only one array and based on the claims runs in O(log^2(n)) and also has close to no explanation of why and how should it work. I have not tried to test it.
In light of controversial claims, I wanted to find out whether it is possible to augment Fenwick tree to answer update(index, value) and findMin(from, to).
If it is possible, I would be happy to hear how it works.
Yes, you can adapt Fenwick Trees (Binary Indexed Trees) to
Update value at a given index in O(log n)
Query minimum value for a range in O(log n) (amortized)
We need 2 Fenwick trees and an additional array holding the real values for nodes.
Suppose we have the following array:
index 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
value 1 0 2 1 1 3 0 4 2 5 2 2 3 1 0
We wave a magic wand and the following trees appear:
Note that in both trees each node represents the minimum value for all nodes within that subtree. For example, in BIT2 node 12 has value 0, which is the minimum value for nodes 12,13,14,15.
Queries
We can efficiently query the minimum value for any range by calculating the minimum of several subtree values and one additional real node value. For example, the minimum value for range [2,7] can be determined by taking the minimum value of BIT2_Node2 (representing nodes 2,3) and BIT1_Node7 (representing node 7), BIT1_Node6 (representing nodes 5,6) and REAL_4 - therefore covering all nodes in [2,7]. But how do we know which sub trees we want to look at?
Query(int a, int b) {
int val = infinity // always holds the known min value for our range
// Start traversing the first tree, BIT1, from the beginning of range, a
int i = a
while (parentOf(i, BIT1) <= b) {
val = min(val, BIT2[i]) // Note: traversing BIT1, yet looking up values in BIT2
i = parentOf(i, BIT1)
}
// Start traversing the second tree, BIT2, from the end of range, b
i = b
while (parentOf(i, BIT2) >= a) {
val = min(val, BIT1[i]) // Note: traversing BIT2, yet looking up values in BIT1
i = parentOf(i, BIT2)
}
val = min(val, REAL[i]) // Explained below
return val
}
It can be mathematically proven that both traversals will end in the same node. That node is a part of our range, yet it is not a part of any subtrees we have looked at. Imagine a case where the (unique) smallest value of our range is in that special node. If we didn't look it up our algorithm would give incorrect results. This is why we have to do that one lookup into the real values array.
To help understand the algorithm I suggest you simulate it with pen & paper, looking up data in the example trees above. For example, a query for range [4,14] would return the minimum of values BIT2_4 (rep. 4,5,6,7), BIT1_14 (rep. 13,14), BIT1_12 (rep. 9,10,11,12) and REAL_8, therefore covering all possible values [4,14].
Updates
Since a node represents the minimum value of itself and its children, changing a node will affect its parents, but not its children. Therefore, to update a tree we start from the node we are modifying and move up all the way to the fictional root node (0 or N+1 depending on which tree).
Suppose we are updating some node in some tree:
If new value < old value, we will always overwrite the value and move up
If new value == old value, we can stop since there will be no more changes cascading upwards
If new value > old value, things get interesting.
If the old value still exists somewhere within that subtree, we are done
If not, we have to find the new minimum value between real[node] and each tree[child_of_node], change tree[node] and move up
Pseudocode for updating node with value v in a tree:
while (node <= n+1) {
if (v > tree[node]) {
if (oldValue == tree[node]) {
v = min(v, real[node])
for-each child {
v = min(v, tree[child])
}
} else break
}
if (v == tree[node]) break
tree[node] = v
node = parentOf(node, tree)
}
Note that oldValue is the original value we replaced, whereas v may be reassigned multiple times as we move up the tree.
Binary Indexing
In my experiments Range Minimum Queries were about twice as fast as a Segment Tree implementation and updates were marginally faster. The main reason for this is using super efficient bitwise operations for moving between nodes. They are very well explained here. Segment Trees are really simple to code so think about is the performance advantage really worth it? The update method of my Fenwick RMQ is 40 lines and took a while to debug. If anyone wants my code I can put it on github. I also produced a brute and test generators to make sure everything works.
I had help understanding this subject & implementing it from the Finnish algorithm community. Source of the image is http://ioinformatics.org/oi/pdf/v9_2015_39_44.pdf, but they credit Fenwick's 1994 paper for it.
The Fenwick tree structure works for addition because addition is invertible. It doesn't work for minimum, because as soon as you have a cell that's supposed to be the minimum of two or more inputs, you've lost information potentially.
If you're willing to double your storage requirements, you can support RMQ with a segment tree that is constructed implicitly, like a binary heap. For an RMQ with n values, store the n values at locations [n, 2n) of an array. Locations [1, n) are aggregates, with the formula A(k) = min(A(2k), A(2k+1)). Location 2n is an infinite sentinel. The update routine should look something like this.
def update(n, a, i, x): # value[i] = x
i += n
a[i] = x
# update the aggregates
while i > 1:
i //= 2
a[i] = min(a[2*i], a[2*i+1])
The multiplies and divides here can be replaced by shifts for efficiency.
The RMQ pseudocode is more delicate. Here's another untested and unoptimized routine.
def rmq(n, a, i, j): # min(value[i:j])
i += n
j += n
x = inf
while i < j:
if i%2 == 0:
i //= 2
else:
x = min(x, a[i])
i = i//2 + 1
if j%2 == 0:
j //= 2
else:
x = min(x, a[j-1])
j //= 2
return x

Algorithm to find the maximum non-adjacent sum in n-ary tree

Given an n-ary tree of integers, the task is to find the maximum sum of a subsequence with the constraint that no 2 numbers in the sequence should share a common edge in the tree.
Example:
1
/ \
2 5
/ \
3 4
Maximum non adjacent sum = 3 + 4 + 5 = 12
The following is the faulty extension of the algorithm outlined in http://www.geeksforgeeks.org/maximum-sum-such-that-no-two-elements-are-adjacent?
def max_sum(node, inc_sum, exc_sum):
for child in node.children:
exc_new = max(inc_sum, exc_sum)
inc_sum = exc_sum + child.val
exc_sum = exc_new
inc_sum, exc_sum = max(max_sum(child, inc_sum, exc_sum),
max_sum(child, inc_sum, inc_sum - node.val))
return exc_sum, inc_sum
But I wasn't sure if swapping exc_sum and inc_sum while returning is the right way to achieve the result and how do I keep track of the possible sums which can lead to a maximum sum, in this example, the maximum sum in the left subtree is (1+3+4) whereas the sum which leads to the final maximum is (3+4+5), so how should (3+4) be tracked? Should all the intermediary sums stored in a table?
Lets say dp[u][select] stores the answer: maximum sub sequence sum with no two nodes having edge such that we consider only the sub-tree rooted at node u ( such that u is selected or not ). Now you can write a recursive program where state of each recursion is (u,select) where u means root of the sub graph being considered and select means whether or not we select node u. So we get the following pseudo code
/* Initialize dp[][] to be -1 for all values (u,select) */
/* Select is 0 or 1 for false/true respectively */
int func(int node , int select )
{
if(dp[node][select] != -1)return dp[node][select];
int ans = 0,i;
// assuming value of node is same as node number
if(select)ans=node;
//edges[i] stores children of node i
for(i=0;i<edges[node].size();i++)
{
if(select)ans=ans+func(edges[node][i],1-select);
else ans=ans+max(func(edges[node][i],0),func(edges[node][i],1));
}
dp[node][select] = ans;
return ans;
}
// from main call, root is root of tree and answer is
// your final answer
answer = max(func(root,0),func(root,1));
We have used memoization in addition to recursion to reduce time complexity.Its O(V+E) in both space and time. You can see here a working version of
the code Code. Click on the fork on top right corner to run on test case
4 1
1 2
1 5
2 3
2 4
It gives output 12 as expected.
The input format is specified in comments in the code along with other clarifications. Its in C++ but there is not significant changes if you want it in python once you understand the code. Do post in comments if you have any doubts regarding the code.

Minesweeper master from Google Code Jam(2014) Qualification round

This is a problem from Google Code Jam qualification round (which is over now). How to solve this problem?
Note: If you have a different method from the ones discussed in answers, please share it so we can expand our knowledge of the different ways to solve this problem.
Problem Statement:
Minesweeper is a computer game that became popular in the 1980s, and is still included in some versions of the Microsoft Windows operating system. This problem has a similar idea, but it does not assume you have played Minesweeper.
In this problem, you are playing a game on a grid of identical cells. The content of each cell is initially hidden. There are M mines hidden in M different cells of the grid. No other cells contain mines. You may click on any cell to reveal it. If the revealed cell contains a mine, then the game is over, and you lose. Otherwise, the revealed cell will contain a digit between 0 and 8, inclusive, which corresponds to the number of neighboring cells that contain mines. Two cells are neighbors if they share a corner or an edge. Additionally, if the revealed cell contains a 0, then all of the neighbors of the revealed cell are automatically revealed as well, recursively. When all the cells that don't contain mines have been revealed, the game ends, and you win.
For example, an initial configuration of the board may look like this ('*' denotes a mine, and 'c' is the first clicked cell):
*..*...**.
....*.....
..c..*....
........*.
..........
There are no mines adjacent to the clicked cell, so when it is revealed, it becomes a 0, and its 8 adjacent cells are revealed as well. This process continues, resulting in the following board:
*..*...**.
1112*.....
00012*....
00001111*.
00000001..
At this point, there are still un-revealed cells that do not contain mines (denoted by '.' characters), so the player has to click again in order to continue the game.
You want to win the game as quickly as possible. There is nothing quicker than winning in one click. Given the size of the board (R x C) and the number of hidden mines M, is it possible (however unlikely) to win in one click? You may choose where you click. If it is possible, then print any valid mine configuration and the coordinates of your click, following the specifications in the Output section. Otherwise, print "Impossible".
My Tried Solution:
So for the solution, you need to make sure that each non-mine node is in a 3x3 matrix with other non-mine nodes, or a 3x2 or 2x2 matrix if the node is on an edge of the grid; lets call this a 0Matrix. So any node in a 0Matrix have all non-mine neighbors.
Firstly, Check whether less mines are required, or less empty nodes
if(# mines required < 1/3 of total grid size)
// Initialize the grid to all clear nodes and populate the mines
foreach (Node A : the set of non-mine nodes)
foreach (Node AN : A.neighbors)
if AN forms a OMatrix with it's neighbors, continue
else break;
// If we got here means we can make A a mine since all of it's neighbors
// form 0Matricies with their other neighbors
// End this loop when we've added the number of mines required
else
// We initialize the grid to all mines and populate the clear nodes
// Here I handle grids > 3x3;
// For smaller grids, I hard coded the logic, eg: 1xn grids, you just populate in 1 dimension
// Now we know that the # clear nodes required will be 3n+2 or 3n+4
// eg: if a 4x4 grid need 8 clear nodes : 3(2) + 2
For (1 -> num 3's needed)
Add 3 nodes going horizontally
When horizontal axis is filled, add 3 nodes going vertically
When vertical axis is filled, go back to horizontal then vertical and so on.
for(1 -> num 2's needed)
Add 2 nodes going horizontally or continuing in the direction from above
When horizontal axis is filled, add 2 nodes going vertically
For example, say we have an 4x4 grid needing 8 clean nodes, here are the steps:
// Initial grid of all mines
* * * *
* * * *
* * * *
* * * *
// Populating 3's horizontally
. * * *
. * * *
. * * *
* * * *
. . * *
. . * *
. . * *
* * * *
// Populating 2's continuing in the same direction as 3's
. . . *
. . . *
. . * *
* * * *
Another Example: 4x4 grid with 11 clear nodes needed; output:
. . . .
. . . .
. . . *
* * * *
Another Example: 4x4 grid with 14 clear nodes needed; output:
// Insert the 4 3's horizontally, then switch to vertical to insert the 2's
. . . .
. . . .
. . . .
. . * *
Now here we have a grid that is fully populated and can be solved in one click if we click on (0, 0).
My solution works for most cases, but it didn't pass the submission (I did check an entire 225 cases output file), so I'm guessing it has some problems, and I'm pretty sure there are better solutions.
Algorithm
Let's first define N, the number of non-mine cells:
N = R * C - M
A simple solution is to fill an area of N non-mine cells line-by-line from top to bottom. Example for R=5, C=5, M=12:
c....
.....
...**
*****
*****
That is:
Always start in the top-left corner.
Fill N / C rows with non-mines from top to bottom.
Fill the next line with N % C non-mines from left to right.
Fill the rest with mines.
There are only a few special cases you have to care about.
Single non-mine
If N=1, any configuration is a correct solution.
Single row or single column
If R=1, simply fill in the N non-mines from left-to-right. If C=1, fill N rows with a (single) non-mine.
Too few non-mines
If N is even, it must be >= 4.
If N is odd, it must be >= 9. Also, R and C must be >= 3.
Otherwise there's no solution.
Can't fill first two rows
If N is even and you can't fill at least two rows with non-mines, then fill the first two rows with N / 2 non-mines.
If N is odd and you can't fill at least two rows with non-mines and a third row with 3 non-mines, then fill the first two rows with (N - 3) / 2 non-mines and the third row with 3 non-mines.
Single non-mine in the last row
If N % C = 1, move the final non-mine from the last full row to the next row.
Example for R=5, C=5, M=9:
c....
.....
....*
..***
*****
Summary
It is possible to write an algorithm that implements these rules and returns a description of the resulting mine field in O(1). Drawing the grid takes O(R*C), of course. I also wrote an implementation in Perl based on these ideas which was accepted by the Code Jam Judge.
There is a more general solution to this problem that passes both the small and large test cases. It avoids having to think of all the special cases, it doesn't care what the dimensions of the board are and doesn't require any back tracking.
ALGORITHM
The basic idea is start with a grid full of mines and remove them starting from cell {0, 0} until there are the correct number of mines on the board.
Obviously there needs to be some way to determine which mines to remove next and when it is impossible to remove the correct number of mines. To do this we can keep an int[][] that represents the board. Each cell with a mine contains -1 and those without mines contain an integer which is the number of mines adjacent to the cell; the same as in the actual game.
Also define the concept of a 'frontier' which is all non-mine cells that are non-zero i.e. those cells with mines adjacent.
For example the configuration:
c . *
. . *
. . *
* * *
Would be represented as:
0 2 -1
0 3 -1
2 5 -1
-1 -1 -1
And the frontier would contain the cells with values: 2, 3, 5, 2
When removing the mines the strategy is:
Find a cell in the frontier that has the same value as the remaining number of mines to remove. So in the example above if we had 5 more mines to remove, the cells with value 5 on the frontier would be chosen.
Failing that chose the smallest frontier cell. So either of the 2's in the example above.
If the value of the chosen cell is greater than the number of mines left to remove then it's impossible to build this board, so return false.
Else remove all mines surrounding the chosen frontier cell.
Repeat until the correct number of mines are present on the board - the constraints of the problem have been met.
In java this looks like:
// Tries to build a board based on the nMines in the test case
private static boolean buildBoard(TestCase t) throws Exception {
if (t.nMines >= t.Board.rows() * t.Board.cols()) {
return false;
}
// Have to remove the cell at 0,0 as the click will go there
t.Board.removeMine(0, 0);
while (!t.boardComplete()) {
Cell c = nextCell(t);
// If the value of this cell is greater than what we need to remove we can't build a board
if (t.Board.getCell(c.getRow(), c.getCol()) > t.removalsLeft()) {
return false;
}
t.Board.removeNeighbourMines(c.getRow(), c.getCol());
}
return true;
}
// Find frontier cell matching removals left, else pick the smallest valued cell to keep things balanced
private static Cell nextCell(TestCase t) {
Cell minCell = null;
int minVal = Integer.MAX_VALUE;
for (Cell c : t.Board.getFrontier()) {
int cellVal = t.Board.getCell(c.getRow(), c.getCol());
if (cellVal == t.removalsLeft()) {
return c;
}
if (cellVal < minVal) {
minVal = cellVal;
minCell = c;
}
}
if (minCell == null) {
throw new NullPointerException("The min cell wasn't set");
}
return minCell;
}
PROOF / INTUITION
Firstly a board is defined as valid if it can be solved by a single click, even if there is only one cell on the board where this click can occur. Therefore for a board to be valid all non-mine cells must be adjacent to a cell with value 0, if this is not the case the cell is defined as unreachable. This is because we know with certainty that all cells adjacent to a 0 cell are non mines, so they can be safely revealed and the game will do it automatically for the player.
A key point to prove for this algorithm is that it is always necessary to remove all the mines surrounding the smallest frontier cell in order to keep the board in a valid state. This is quite easy to prove just by drawing out a board (such as the one above) and picking the lowest value cell (in this case the top right 2). If only a single mine is removed then the board would not be valid, it would be in either of these two states:
0 1 1
0 2 -1
2 5 -1
-1 -1 -1
or
0 1 -1
0 2 2
2 5 -1
-1 -1 -1
which both have unreachable cells.
So it is now true that always choosing the smallest frontier cell will keep the board in a valid state and my first instinct was that continuing to choose these cells would go through all valid states, however this is not correct. This can be illustrated by a test case such as 4 4 7 (so there are 9 non-mine cells). Then consider the following board:
0 2 -1 -1
2 5 -1 -1
-1 -1 -1 -1
-1 -1 -1 -1
Continuing to chose the smallest frontier cell may result in the algorithm doing the following:
0 2 -1 -1
0 3 -1 -1
0 3 -1 -1
0 2 -1 -1
Which means it is now impossible to remove just a single mine to complete the board for this case. However choosing a frontier cell that matches the number of remaining mines (if one exists) ensures that the 5 would have been chosen resulting in a 3x3 square of non-mines and a correct solution to the test case.
At this point I decided to give the algorithm a try on all test cases in the following range:
0 < R < 20
0 < C < 20
0 ≤ M < R * C
and found that it managed to correctly identify all the impossible configurations and build what looked like sensible solutions to the possible configurations.
Further intuition behind why choosing the frontier cell with the same value as the remaining number of mines (should it exist) is correct is that it allows the algorithm to find configurations for solutions requiring an odd number of non-mines.
When originally implementing this algorithm I was intending on writing heuristics that built the non-mine area in a square arrangement. Considering the 4 4 7 test case again it would end-up doing this:
0 0 2 -1
0 1 4 -1
2 4 -1 -1
-1 -1 -1 -1
notice how we now have a 1 on the frontier which would ensure the final cell removed completed the square to give:
c . . *
. . . *
. . . *
* * * *
This would mean the heuristics change slightly to:
Pick the smallest frontier cell
In the case of a tie, pick the first cell added to the frontier list
This could be implemented by keeping a FIFO queue of frontier cells, but I quickly realised that it is trickier than it first seems. This is due to the fact that the values of the frontier cells are interdependent and so care needs to be taken to keep the collection of frontier cells in the correct state and also not to use the cells value in any kind of hash value etc. I'm sure this could be done, but upon realising that just adding the extra heuristic to pick any cells with values equal to the remaining removals worked, this seemed liked the easier approach.
This is my code. I solved taking different cases like if number of rows=1 or number of columns=1 or if number of mines=(r*c)-1 and few other cases.
The position on the layout to click is placed at a[r-1][c-1]('0' indexed) every time.
For this question I had given few wrong attempts and every time I kept finding a new case. I eliminated few cases in which solution is not possible using goto and let it jump to end where it prints out impossible. A very simple solution(Indeed can be said a brute force solution since I coded for different cases possible individually). This is an editorial for my code. And on github.
I used search with backtracking, but I could solve only the small input.
Basically the algorithm starts with the board full of mines and tries to remove the mines in a way that the first "click" would solve the board. The catch is that to allow a "click" to expand to another cell, the expansion will come from another cell that must have all other neighbor cells cleared too. Sometimes, to expand to another cell you would need to remove other mines and end up with less mines than required. The algorithm will backtrack if it reaches such a position.
Maybe it is simpler to do the opposite. Start with an empty board and add each mine in a way that would not prevent the "expansion" of the initial click.
The full Python code is below:
directions = [
[-1, -1], [-1, 0], [-1, 1],
[0, -1], [0, 1],
[1, -1], [1, 0], [1, 1],
]
def solve(R, C, M):
def neighbors(i, j):
for di, dj in directions:
if 0 <= (i + di) < R and 0 <= (j + dj) < C:
yield (i + di, j + dj)
def neighbors_to_clear(i, j, board):
return [(ni, nj) for ni, nj in neighbors(i, j) if board[ni][nj] == "*"]
def clear_board(order):
to_clear = R * C - M - 1
board = [["*" for _ in range(C)] for _ in range(R)]
for i, j in order:
board[i][j] = "."
for ni, nj in neighbors_to_clear(i, j, board):
to_clear -= 1
board[ni][nj] = "."
return board, to_clear
def search(ci, cj):
nodes = []
board = []
to_clear = 1
nodes.append((ci, cj, []))
while nodes and to_clear > 0:
i, j, order = nodes.pop()
board, to_clear = clear_board(order)
neworder = order + [(i, j)]
if to_clear == 0:
board[ci][cj] = "c"
return board
elif to_clear > 0:
for ni, nj in neighbors_to_clear(i, j, board):
board[ni][nj] = "."
nodes.append([ni, nj, neworder])
for i in range(R):
for j in range(C):
board = search(i, j)
if board:
for row in board:
print "".join(row)
return
print "Impossible"
return
T = int(raw_input())
for i in range(1, T + 1):
R, C, M = map(int, raw_input().split(" "))
print("Case #%d:" % i)
solve(R, C, M)
my strategy was very similar to yours and I passed both small and large.
Did you think about cases below?
R * C - M = 1
There is only one row
There are only two rows
I flipped R and C when R > C.
I separated this into two initial special cases, then had a general algorithm. The tl;dr version is to build a square of blank spaces from the top left. Similar to other answers, but with fewer special cases.
Special cases
Case 1
Only 1 blank space. Just click in the top left corner and finish.
Case 2
2 or 3 blank spaces, with a grid that is not either Rx1 or 1xC. This is impossible, so we fail early.
Algorithm
Always click in the top left corner. Start with a 2x2 blank square in the top left (we have at least 4 blanks). Now we need to add the remaining blanks. We then expand the square along one edge then the other, until we have no more blank spaces.
Example of blanking order:
C 2 6 12
1 3 7 13
4 5 8 14
9 10 11 15
Impossible case
Note that when beginning a new edge, we must place at least two blank spaces for this to be valid. So if we have only one blank to place, then this must be invalid (unless our edge has length one). My logic looked like this:
if maxEdgeLength > 1 and remainingBlanks == 1:
print('Impossible')
return
However, we could have left off the end of the last edge, which would give us two blanks now. Of course we can only leave off the last blank if the last edge was more than 2 blanks long!
My logic for this special case looked like this:
if remainingBlanks == 1 and lastEdgeSize > 2:
mineMatrix[lastBlank] = '*'
blanks += 1
Code z self explanatory with comments. O(r+c)
import java.util.Scanner;
public class Minesweeper {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
for(int j=0;j<n;j++) {
int r =sc.nextInt(),
c = sc.nextInt(),
m=sc.nextInt();
//handling for only one space.
if(r*c-m==1) {
System.out.println("Case #"+(int)(j+1)+":");
String a[][] = new String[r][c];
completeFill(a,r-1,c-1,"*");
printAll(a, r-1, c-1);
}
//handling for 2 rows or cols if num of mines - r*c < 2 not possible.
//missed here the handling of one mine.
else if(r<2||c<2) {
if(((r*c) - m) <2) {
System.out.println("Case #"+(int)(j+1)+":");
System.out.println("Impossible");
}
else {
System.out.println("Case #"+(int)(j+1)+":");
draw(r,c,m);
}
}
//for all remaining cases r*c - <4 as the click box needs to be zero to propagate
else if(((r*c) - m) <4) {
System.out.println("Case #"+(int)(j+1)+":");
System.out.println("Impossible");
}
//edge cases found during execution.
//row or col =2 and m=1 then not possible.
//row==3 and col==3 and m==2 not possible.
else {
System.out.println("Case #"+(int)(j+1)+":");
if(r==3&&m==2&&c==3|| r==2&&m==1 || c==2&&m==1) {
System.out.println("Impossible");
}
else {
draw(r,c,m);
}
}
}
}
/*ALGO : IF m < (r and c) then reduce r or c which ever z max
* by two first time then on reduce by factor 1.
* Then give the input to filling (squarefill) function which files max one line
* with given input. and returns the vals of remaining rows and cols.
* checking the r,c==2 and r,c==3 edge cases.
**/
public static void draw(int r,int c, int m) {
String a[][] = new String[r][c];
int norow=r-1,nocol=c-1;
completeFill(a,norow,nocol,".");
int startR=0,startC=0;
int red = 2;
norow = r;
nocol = c;
int row=r,col=c;
boolean first = true;
boolean print =true;
while(m>0&&norow>0&&nocol>0) {
if(m<norow&&m<nocol) {
if(norow>nocol) {
norow=norow-red;
//startR = startR + red;
}
else if(norow<nocol){
nocol=nocol-red;
//startC = startC + red;
}
else {
if(r>c) {
norow=norow-red;
}
else {
nocol=nocol-red;
}
}
red=1;
}
else {
int[] temp = squareFill(a, norow, nocol, startR, startC, m,row,col,first);
norow = temp[0];
nocol = temp[1];
startR =r- temp[0];
startC =c -temp[1];
row = temp[3];
col = temp[4];
m = temp[2];
red=2;
//System.out.println(norow + " "+ nocol+ " "+m);
if(norow==3&&nocol==3&&m==2 || norow==2&&m==1 || nocol==2&&m==1) {
print =false;
System.out.println("Impossible");
break;
}
}
first = false;
}
//rectFill(a, 1, r, 1, c);
if(print)
printAll(a, r-1, c-1);
}
public static void completeFill(String[][] a,int row,int col,String x) {
for(int i=0;i<=row;i++) {
for(int j=0;j<=col;j++) {
a[i][j] = x;
}
}
a[row][col] = "c";
}
public static void printAll(String[][] a,int row,int col) {
for(int i=0;i<=row;i++) {
for(int j=0;j<=col;j++) {
System.out.print(a[i][j]);
}
System.out.println();
}
}
public static int[] squareFill(String[][] a,int norow,int nocol,int startR,int startC,int m,int r, int c, boolean first) {
if(norow < nocol) {
int fil = 1;
m = m - norow;
for(int i=startR;i<startR+norow;i++) {
for(int j=startC;j<startC+fil;j++) {
a[i][j] = "*";
}
}
nocol= nocol-fil;
c = nocol;
norow = r;
}
else {
int fil = 1;
m = m-nocol;
for(int i=startR;i<startR+fil;i++) {
for(int j=startC;j<startC+nocol;j++) {
a[i][j] = "*";
}
}
norow = norow-fil;
r= norow;
nocol = c;
}
return new int[] {norow,nocol,m,r,c};
}
}
My approach to this problem was as follows:
For a 1x1 grid, M has to be zero otherwise it's impossible
For a Rx1 or 1xC grid, we need M <= R * C - 2 (place 'c' on the last cell with an empty cell next to it)
For a RxC grid, we need M <= R * C - 4 (place 'c' on a corner with 3 empty cells around it)
In summary, c will always have non-mine cells next to it no matter what, otherwise it's impossible. This solution makes sense to me, and I have checked the output against their sample and small inputs, however it was not accepted.
Here is my code:
import sys
fname = sys.argv[1]
handler = open(fname, "r")
lines = [line.strip() for line in handler]
testcases_count = int(lines.pop(0))
def generate_config(R, C, M):
mines = M
config = []
for row in range(1, R+1):
if mines >= C:
if row >= R - 1:
config.append(''.join(['*' * (C - 2), '.' * 2]))
mines = mines - C + 2
else:
config.append(''.join('*' * C))
mines = mines - C
elif mines > 0:
if row == R - 1 and mines >= C - 2:
partial_mines = min(mines, C - 2)
config.append(''.join(['*' * partial_mines, '.' * (C - partial_mines)]))
mines = mines - partial_mines
else:
config.append(''.join(['*' * mines, '.' * (C - mines)]))
mines = 0
else:
config.append(''.join('.' * C))
# click the last empty cell
config[-1] = ''.join([config[-1][:-1], 'c'])
return config
for case in range(testcases_count):
R, C, M = map(int, lines.pop(0).split(' '))
# for a 1x1 grid, M has to be zero
# for a Rx1 or 1xC grid, we must have M <= # of cells - 2
# for others, we need at least 4 empty cells
config_possible = (R == 1 and C == 1 and M==0) or ((R == 1 or C == 1) and M <= R * C - 2) or (R > 1 and C > 1 and M <= R * C - 4)
config = generate_config(R, C, M) if config_possible else None
print "Case #%d:" % (case+1)
if config:
for line in config: print line
else:
print "Impossible"
handler.close()
It worked pretty well against their sample on the website and against the small input they provided, but it looks like I'm missing something.
Here is the output to the sample:
Case #1:
Impossible
Case #2:
*
.
c
Case #3:
Impossible
Case #4:
***....
.......
.......
......c
Case #5:
**********
**********
**********
**********
**********
**********
**********
**********
**........
.........c
Update: Reading vinaykumar's editorial, I understand what's wrong with my solution. Basic rules of minesweeper that I should have covered, pretty much.
Pre-Checks
M = (R * C) - 1
Fill grid with all mines and put click anywhere.
R == 1 || C == 1
Fill left/right (or up/down) in order: click, non-mines, mines (ex. c...****).
M == (R * C) - 2 || M == (R * C) - 3
Impossible
Algorithm
I started with an "empty" grid (all .s) and placed the click in a corner (I will use the top-left corner for the click, and begin filling with mines from the bottom-right).
We will use R1 and C1 as our "current" rows and columns.
While we have enough mines to fill a row or column which, when removed, does not leave a single row or column left (while((M >= R1 && C1 > 2) || (M >= C1 && R1 > 2))), we "trim" the grid (fill with mines and reduce R1 or C1) using the shortest side and remove that many mines. Thus, a 4x5 with 6 mines left would become a 4x4 with 2 mines left.
If we end up with 2 x n grid we will either have 0 mines (we are done) or 1 mine left (Impossible to win).
If we end up with a 3 x 3 grid we will either have 0 mines (we are done), 1 mine (continue below), or 2 mines (Impossible to win).
Any other combination is winnable. We check if M == min(R1,C1)-1, if so we will need to put a single mine one row or column in from the shortest edge, then fill the shortest edge with the remaining mines.
Example
I will show the order I enter mines into the grid with numbers, just to help with visualization
R = 7, C = 6, M = 29
c...42
....42
...742
..6742
555542
333332
111111
It took me a few different tries to get my algorithm correct, but I wrote mine in PHP and got both the small and large correct.
I tried my luck in this question also but for some reason didn't pass checks.
I figured that it's solvable for (3x3 matrix) if there are less than (rows*cols-4) mines, as I needed only 4 cells for "c" and its boundaries as "."
My algorithms follows:
Solvable?:
Checks if there is enough room for mines (rows*cols - 4 == maximum mines)
Exceptions like rows == 1, cols == 1; then it's rows*cols-2
Conditional whether possible or impossible
Build solution
Build rows*cols matrix, with default value nil
Go to m[0][0] and assign 'c'
Define m[0][0] surroundings with '.'
Loop from bottom right of Matrix and assign '*' until mines are over, then assign '.'
The solution can be found here. Contents of page below.
There are many ways to generate a valid mine configuration. In this
analysis, we try to enumerate all possible cases and try to generate a
valid configuration for each case (if exists). Later, after having
some insight, we provide an easier to implement algorithm to generate
a valid mine configuration (if exists).
Enumerating all possible cases
We start by checking the trivial cases:
If there is only one empty cell, then we can just fill all cells with
mines except the cell where you click. If R = 1 or C = 1, the mines
can be placed from left to right or top to bottom respectively and
click on the right-most or the bottom-most cell respectively. If the
board is not in the two trivial cases above, it means the board has at
least 2 x 2 size. Then, we can manually check that:
If the number of empty cells is 2 or 3, it is Impossible to have a
valid configuration. If R = 2 or C = 2, valid configurations exists
only if M is even. For example, if R = 2, C = 7 and M = 5, it is
Impossible since M is odd. However, if M = 6, we can place the mines
on the left part of the board and click on the bottom right, like
this:
*....
*...c If the board is not in any of the above case, it means the board is at least 3 x 3 size. In this case, we can always
find a valid mine configuration if the number of empty cells is bigger
than 9. Here is one way to do it:
If the number of empty cells is equal or bigger than 3 * C, then the
mines can be placed row by row starting from top to bottom. If the
number of remaining mines can entirely fill the row or is less than C
- 2 then place the mines from left to right in that row. Otherwise, the number of remaining mines is exactly C - 1, place the last mine in
the next row. For example:
****** ******
*****. ****..
...... -> *.....
...... ......
.....c .....c If the number of empty cells is less than 3 * C but at least 9, we first fill all rows with mines except
the last 3 rows. For the last 3 rows, we fill the remaining mines
column by column from the left most column. If the remaining mines on
the last column is two, then last mine must be put in the next column.
For example:
****** ******
.... -> *...
**.... *.....
*....c *....c Now, we are left with at most 9 empty cells which are located in the 3 x 3 square cells at the bottom right
corner. In this case, we can check by hand that if the number of empty
cells is 5 or 7, it is Impossible to have a valid mine configuration.
Otherwise, we can hard-coded a valid configuration for each number of
empty cell in that 3 x 3 square cells.
Sigh... that was a lot of cases to cover! How do we convince ourselves
that when we code the solution, we do not miss any corner case?
Brute-force approach
For the small input, the board size is at most 5 x 5. We can check all
(25 choose M) possible mine configurations and find one that is valid
(i.e., clicking an empty cell in the configuration reveal all other
empty cells). To check whether a mine configuration is valid, we can
run a flood-fill algorithm (or a simple breath-first search) from the
clicked empty cell and verify that all other empty cells are reachable
(i.e., they are in one connected component). Note that we should also
check all possible click positions. This brute-force approach is fast
enough for the small input.
The brute-force approach can be used to check (for small values of R,
C, M) whether there is a false-negative in our enumeration strategy
above. A false-negative is found when there exist a valid mine
configuration, but the enumeration strategy above yields Impossible.
Once we are confident that our enumeration strategy does not produce
any false-negative, we can use it to solve the large input.
An easier to implement approach
After playing around with several valid mine configurations using the
enumeration strategy above, you may notice a pattern: in a valid mine
configuration, the number of mines in a particular row is always equal
or larger than the number of mines of the rows below it and all the
mines are left-aligned in a row. With this insight, we can implement a
simpler backtracking algorithm that places mines row by row from top
to bottom with non-increasing number of mines as we proceed to fill in
the next row and prune if the configuration for the current row is
invalid (it can be checked by clicking at the bottom right cell). This
backtracking with pruning can handle up to 50 x 50 sized board in
reasonable time and is simpler to implement (i.e., no need to
enumerate corner / tricky cases).
If the contest time were shorter, we may not have enough time to
enumerate all possible cases. In this case, betting on the
backtracking algorithm (or any other algorithm that is easier to
implement) may be a good idea. Finding such algorithms is an art :).

Least distance between two values in a large binary tree with duplicate values

Given a binary tree that might contain duplicate values, you need to find minimum distance between two given values. Note that the binary tree can be large.
For example:
5
/ \
1 7
/ \ / \
4 3 8 2
/ \
1 2
The function should return 2 for (1 and 2 as input).
(If duplicates are not present, we can find LCA and then calculate the distance.)
I've written the following code but I couldn't handle cases when the values are present in different subtrees and in the below cases:
root = 1, root.left = 4, root.left.left = 3, root.left.right = 2, root.left.left.left = 1
root = 1, root.left = 4, root.left.left = 3, root.left.left.left = 1, root.left.left.right = 2
void dist(struct node* root,int& min,int n1,int n2,int pos1,int pos2,int level) {
if(!root)
return;
if(root->data==n1){
pos1 = level;
if(pos2>=0)
if(pos1-pos2 < min)
min = pos1-pos2;
}
else if(root->data==n2){
pos2 = level;
if(pos1>=0)
if(pos2-pos1 < min)
min = pos2-pos1;
}
dist(root->left,min,n1,n2,pos1,pos2,level+1);
dist(root->right,min,n1,n2,pos1,pos2,level+1);
}
I think at each node we can find if that node is the LCA of the values or not. If that node is LCA then find the distance and update min accordingly, but this would take O(n2).
Following is an algorithm to solve the problem:-
traverse all of the tree and calculate paths for each node using binary strings representation and store into hash map
eg. For your tree the hashmap will be
1 => 0,000
2 => 001,11
3 => 01
...
When query for distance between (u,v) check for each pair and calculate distance between them. Remove common prefix from strings and then sum the remaining lengths
eg. u=1 and v=2
distance(0,001) = 2
distance(0,11) = 3
distance(000,001) = 2
distance(000,11) = 5
min = 2
Note: I think the second step can be made more efficient but need to do more research
You can compute the LCA of a set of nodes by computing LCA(x1, LCA(x2, LCA(x3... and all the nodes in the set will be somewhere below this LCA. If you compare the LCAs of two sets of nodes and one is not directly beneath the other then the minimum distance between any two nodes in different sets will be at least the distance between the LCAs. If one LCA is above the other then the minimum distance could be zero.
This allows a sort of branch and bound approach. At each point you have a best minimum distance so far (initialized as infinity). Given two sets of nodes, use their LCAs to work out a lower bound on their minimum distance and discard them if this is no better than the best answer so far. If not discarded, split each set into two plus a possible single depending on whether each node in the set is to the left of the LCA, to the right of the LCA, or is the LCA. Recursively check for the minimum distance in the (up to nine) pairs of split sets. If both splits in a pair are below some minimum size, just work out the LCAs and minimum distances of each pair of nodes across the two sets - at this point may find out that you have a new best answer and can update the best answer so far.
Looking at the example at the top of the question, the LCA of the 2s is the root of the tree, and the LCA of the 1s is the highest 1. So the minimum distance between these two sets could be close to zero. Now split each set in two. The left hand 2 is distance two from both of the two 1s. The LCA of the right hand 2 is itself, on the right hand branch of the tree, and the LCA of each of the two 1s is down on the left hand branch of the tree. So the distance between the two is at least two, and we could tell this even if we had a large number of 2s anywhere below the position of the existing right-hand two, and a large number of 1s anywhere on the left hand subtree.
Do a pre-order traversal of the tree (or any traversal should work).
During this process, simply keep track of the closest 1 and 2, and update the distance whenever you find a 2 and the closest 1 is closer than the closest distance so far, or vice versa.
Code (C++, untested first draft): (hardcoded 1 and 2 for simplicity)
int getLeastDistance(Node *n, int *distTo1, int *distTo2)
{
if (n == NULL)
return;
int dist = LARGE_VALUE;
// process current node
if (n->data == 1)
{
dist = *distTo2;
*distTo1 = 0;
}
else if (n->data == 2)
{
dist = *distTo1;
*distTo2 = 0;
}
// go left
int newDistTo1 = *distTo1 + 1,
newDistTo2 = *distTo2 + 1;
dist = min(dist, getLeastDistance(n->left, &newDistTo1, &newDistTo2));
// update distances
*distTo1 = min(*distTo1, newDistTo1 + 1);
*distTo2 = min(*distTo2, newDistTo2 + 1);
// go right
newDistTo1 = *distTo1 + 1;
newDistTo2 = *distTo2 + 1;
dist = min(dist, getLeastDistance(n->right, &newDistTo1, &newDistTo2));
}
Caller:
Node root = ...;
int distTo1 = LARGE_VALUE, distTo2 = LARGE_VALUE;
int dist = getLeastDistance(&root, &distTo1, &distTo2);
Just be sure to make LARGE_VALUE far enough from the maximum value for int such that it won't overflow if incremented (-1 is probably safer, but it requires more complex code).

Hard Coding Depth First Search Results (or Optimizing?)

I need to get all possible paths of a tree so I implemented a DFS like this:
void bisearch(std::vector<int> path, int steps,
int node, std::vector<std::vector<int>> *paths) {
int sum = 0;
if (path.size() == steps) {
for(std::vector<int>::iterator it=path.begin(); it != path.end(); ++it) {
sum += (*it);
}
if (sum == node)
paths->push_back(path);
}
else {
std::vector<int> uPath(path);
uPath.push_back(1);
bisearch(uPath, steps, node, paths);
std::vector<int> dPath(path);
dPath.push_back(0);
bisearch(dPath, steps, node, paths);
}
}
The above code gives me all paths to some ending node for a tree of length "steps". I then loop through all ending nodes and run this to get every path. Issue is it takes forever! I was thinking of maybe hardcoding all the possible combinations to speed it up, of course I couldn't do this by hand since for instance a tree with 25 steps would have 2^25 ~= 35 million possible combinations, but maybe I could print the output from the search and use that to hardcode? Or does anyone see any easy optimizations I could make that would make a big difference on the performance? Thanks.
EDIT: Let me clarify a little. I need the path, that is the sequence of movements along the tree where 1 represents a right hand move and 0 a left (or up/down whichever you prefer). So for instance a 2 step tree I need the four ordered pairs (1,0) (0,1) (1,1) (0,0).
Since "all the combinations" should mean just "the combinations of turning right / left at a certain level", you could just loop through 0 to 2 ^ n - 1, and the binary representation padded with 0 in the front might be just what you want.
If what you want is the count of paths with left turn count equals to a certain number k, then this just equals the numbers from 0 to 2 ^ n - 1 that has k bit equal to 1, and you could possibly use this to compute the result you want.

Resources