Related
Recently I came across this question and I have no clue where or how to start solving it. Here is the question:
There are 8 statues 0,1,2,3,4,5,6,7 . Each statue is pointing in one of the following four direction North, South, East or West. John would like to arrange the statues so that they all point in same direction. However John is restricted to the following 8 moves which correspond to rotation each statue listed 90 degrees clockwise. (N to E, E to S, S to W, W to N)
Moves
A: 0,1
B: 0,1,2
C: 1,4,5,6
D: 2,5
E: 3,5
F: 3,7
G: 5,7
H: 6,7
Help John figure out fewest number of moves to help point all statues in one direction.
Input : A string initialpos consisting of 8 chars. Each char is either 'N,'S,'E,'W'
Output: An integer which represents fewest no. of moves needed to arrange statues in same direction. If no sequence possible then return -1.
Sample test cases:
input: SSSSSSSS
Output: 0
Explanation: All statues point in same direction. So it takes 0 moves
Test case 1:
Input : WWNNNNNN
Output: 1
Exp: John can use Move A which will make all statues point to North
Test Case 3:
input: NNSEWSWN
Output: 6
Exp: John uses Move A twice, B once, F twice, G once. This will result in all statues facing W.
The only approach I was able to think of was to brute force it. But since the moves can be done multiple times (test case 3), what would be the limit to applying the moves before we conclude that such an arrangement is not possible (i.e output -1)? I am looking for specific types of algorithms that can be used to solve this, also what part of the problem is used in identifying an algorithm.
Note that the order of moves makes no difference, only the set (with repetition). Also note that making the same move 4 times is equivalent to doing nothing, so there is never any reason to make the same move more than 3 times. This reduces the space to 48 possible sequences, which isn't too terrible, but we can still do better than brute force.
The only move that treats 0 and 1 differently is C, so apply C as many times as is necessary to bring 0 and 1 into alignment. We mustn't use C any more than that, and C is the only thing that can move 4, so the remaining task is to align everything to 4.
The only way to move 6 is with H; apply H to align 6.
Now to align 3 and 7. We could do it with E and G, but we may have the option to use F as a short-cut. The optimal number of F moves is not yet clear, so we'll use E and G, and come back to F later.
Apply D to align 5.
Apply B to align 2.
Apply A to align 0 and 1.
Now revisit F, and see whether the short-cut actually saves moves. Pick the optimal number of F moves. (This is easy even by brute force, since there are only 4 possibilities to test.)
The directions N, E, W, S with operation of turning are congruent with Z mod 4 with succ: turn N = (succ 0) mod 4, turn W twice = (succ succ 2) mod 4 etc.
Each move is a vector of zeros (no change) and ones (turn by one) being added to inputs: say you have your example of NNSEWSWN, which would be [0, 0, 2, 1, 3, 2, 3, 0], and you push the button A, which is [1, 1, 0, 0, 0, 0, 0, 0], resulting in [1, 1, 2, 1, 3, 2, 3, 0], or EESEWSWN.
Now if you do a bunch of different operations, they all add up. Thus, you can represent the whole system with this matrix equation:
(start + move_matrix * applied_moves) mod 4 = finish
where start and finish are position vectors as described above, move_matrix the 8x8 matrix with all the moves, and applied_moves a 8-element vector saying how many times we push each button (in range 0..3).
From this, you can get:
applied_moves = (inverse(move_matrix) * (finish - start)) mod 4
Number of applied moves is then just this:
num_applied_moves = sum((inverse(move_matrix) * (finish - start)) mod 4)
Now just plug in the four different values for finish and see which one is least.
You can use matlab, numpy, octave, APL, whatever rocks your boat, as long as it supports matrix algebra, to get your answer very quickly and very easily.
This sounds a little like homework... but I would go with this line of logic.
Run a loop seeing how many moves it would take to move all the statues to face one direction. You would get something like allEast = 30, allWest = 5, etc. Take the lowest sum and corresponding direction would be the answer. With that mindset its pretty easy to build an algorithm to handle computation.
Brute-force could work. A move applied 4 times is the same as not applying the move at all, so each move can only be applied 0, 1, 2, or 3 times.
The order of the moves does not matter. Move a followed by b is the same as b followed by a.
So there are only 4^8 = 65536 possible combinations of moves.
A general solution is to note that there are only 4^8 = 64k different configurations. Each move can therefore be represented as a table of 64k 2 byte indices taking one configuration to the next. The 2 bytes e.g. are divided into 8 2-bit fields 0=N, 1=E, 2=S, 3=W. Further we can use one more table of bits to say which of the 64k configurations have all statues pointing in the same direction.
These tables don't need to be computed at run time. They can be preprocessed while writing the program and stored.
Let table A[c] give the configuration resulting after applying move A to configuration c. and Z[c] return true iff c is a successful config.
So we can use a kind of BFS:
1. Let C be a set of configurations, initially C = { s } where s is the starting config
2. Let n = 0
3. If Z[c] is true for any c in C, return n
4. Let C' be the result of applying A, B, ... H to each element of C.
5. Set C = C', n = n + 1 and go to 3
C can theoretically grow to be almost 64k in size, but the bigger it gets, the better the chances of success, so this ought to be quite fast in practice.
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 :).
I am trying to implement the Parallel Algorithm for Longest Common Subsequence Problem described in http://www.iaeng.org/publication/WCE2010/WCE2010_pp499-504.pdf
But i am having a problem with the variable C in Equation 6 on page 4
The paper refered to C on at the end of page 3 as
C as Let C[1 : l] bethe finite alphabet
I am not sure what is ment by this, as i guess it would it with the 2 strings ABCDEF and ABQXYEF be ABCDEFQXY. But what if my 2 stings is a list of objects (Where my match test for an example is obj1.Name = obj2.Name), what would my C be here? just a union on the 2 arrays?
Having read and studied the paper, I can say that C is supposed to be an array holding the alphabet of your strings, where the alphabet size (and, thus, the size of C) is l.
By the looks of your question, however, I feel the need to go deeper on this, because it looks like you didn't get the whole picture yet. What is P[i,j], and why do you need it? The answer is that you don't really need it, but it's an elegant optimization. In page 3, a little bit before Theorem 1, it is said that:
[...] This process ends when j-k = 0 at the k-th step, or a(i) =
b(j-k) at the k-th step. Assume that the process stops at the k-th
step, and k must be the minimum number that makes a(i) = b(j-k) or j-k
= 0. [...]
The recurrence relation in (3) is equivalent to (2), but the fundamental difference is that (2) expands recursively, whereas with (3) you never have recursive calls, provided that you know k. In other words, the magic behind (3) not expanding recursively is that you somehow know the spot where the recursion on (2) would stop, so you look at that cell immediately, rather than recursively approaching it.
Ok then, but how do you find out the value for k? Since k is the spot where (2) reaches a base case, it can be seen that k is the amount of columns that you have to "go back" on B until you are either off the limits (i.e., the first column that is filled with 0's) OR you find a match between a character in B and a character in A (which corresponds to the base case conditions in (2)). Remember that you will be matching the character a(i-1), where i is the current row.
So, what you really want is to find the last position in B before j where the character a(i-1) appears. If no such character ever appears in B before j, then that would be equivalent to reaching the case i = 0 or j-1 = 0 in (2); otherwise, it's the same as reaching a(i) = b(j-1) in (2).
Let's look at an example:
Consider that the algorithm is working on computing the values for i = 2 and j = 3 (the row and column are highlighted in gray). Imagine that the algorithm is working on the cell highlighted in black and is applying (2) to determine the value of S[2,2] (the position to the left of the black one). By applying (2), it would then start by looking at a(2) and b(2). a(2) is C, b(2) is G, to there's no match (this is the same procedure as the original, well-known algorithm). The algorithm now wants to find the value of S[2,2], because it is needed to compute S[2,3] (where we are). S[2,2] is not known yet, but the paper shows that it is possible to determine that value without refering to the row with i = 2. In (2), the 3rd case is chosen: S[2,2] = max(S[1, 2], S[2, 1]). Notice, if you will, that all this formula is doing is looking at the positions that would have been used to calculate S[2,2]. So, to rephrase that: we're computing S[2,3], we need S[2,2] for that, we don't know it yet, so we're going back on the table to see what's the value of S[2,2] in pretty much the same way we did in the original, non-parallel algorithm.
When will this stop? In this example, it will stop when we find the letter C (this is our a(i)) in TGTTCGACA before the second T (the letter on the current column) OR when we reach column 0. Because there is no C before T, we reach column 0. Another example:
Here, (2) would stop with j-1 = 5, because that is the last position in TGTTCGACA where C shows up. Thus, the recursion reaches the base case a(i) = b(j-1) when j-1 = 5.
With this in mind, we can see a shortcut here: if you could somehow know the amount k such that j-1-k is a base case in (2), then you wouldn't have to go through the score table to find the base case.
That's the whole idea behind P[i,j]. P is a table where you lay down the whole alphabet vertically (on the left side); the string B is, once again, placed horizontally in the upper side. This table is computed as part of a preprocessing step, and it will tell you exactly what you will need to know ahead of time: for each position j in B, it says, for each character C[i] in C (the alphabet), what is the last position in B before j where C[i] is found (note that i is used to index C, the alphabet, and not the string A. Maybe the authors should have used another index variable to avoid confusion).
So, you can think of the semantics for an entry P[i,j] as something along the lines of: The last position in B where I saw C[i] before position j. For example, if you alphabet is sigma = {A, E, I, O, U}, and B = "AOOIUEI", thenP` is:
Take the time to understand this table. Note the row for O. Remember: this row lists, for every position in B, where is the last known "O". Only when j = 3 will we have a value that is not zero (it's 2), because that's the position after the first O in AOOIUEI. This entry says that the last position in B where O was seen before is position 2 (and, indeed, B[2] is an O, the one that follows A). Notice, in that same row, that for j = 4, we have the value 3, because now the last position for O is the one that correspnds to the second O in B (and since no more O's exist, the rest of the row will be 3).
Recall that building P is a preprocessing step necessary if you want to easily find the value of k that makes the recursion from equation (2) stop. It should make sense by now that P[i,j] is the k you're looking for in (3). With P, you can determine that value in O(1) time.
Thus, the C[i] in (6) is a letter of the alphabet - the letter that we are currently considering. In the example above, C = [A,E,I,O,U], and C[1] = A, C[2] = E, etc. In equaton (7), c is the position in C where a(i) (the current letter of string A being considered) lives. It makes sense: after all, when building the score table position S[i,j], we want to use P to find the value of k - we want to know where was the last time we saw an a(i) in B before j. We do that by reading P[index_of(a(i)), j].
Ok, now that you understand the use of P, let's see what's happening with your implementation.
About your specific case
In the paper, P is shown as a table that lists the whole alphabet. It is a good idea to iterate through the alphabet because the typical uses of this algorithm are in bioinformatics, where the alphabet is much, much smaller than the string A, making the iteration through the alphabet cheaper.
Because your strings are sequences of objects, your C would be the set of all possible objects, so you'd have to build a table P with the set of all possible object instance (nonsense, of course). This is definitely a case where the alphabet size is huge when compared to your string size. However, note that you will only be indexing P in those rows that correspond to letters from A: any row in P for a letter C[i] that is not in A is useless and will never be used. This makes your life easier, because it means you can build P with the string A instead of using the alphabet of every possible object.
Again, an example: if your alphabet is AEIOU, A is EEI and B is AOOIUEI, you will only be indexing P in the rows for E and I, so that's all you need in P:
This works and suffices, because in (7), P[c,j] is the entry in P for the character c, and c is the index of a(i). In other words: C[c] always belongs to A, so it makes perfect sense to build P for the characters of A instead of using the whole alphabet for the cases where the size of A is considerably smaller than the size of C.
All you have to do now is to apply the same principle to whatever your objects are.
I really don't know how to explain it any better. This may be a little dense at first. Make sure to re-read it until you really get it - and I mean every little detail. You have to master this before thinking about implementing it.
NOTE: You said you were looking for a credible and / or official source. I'm just another CS student, so I'm not an official source, but I think I can be considered "credible". I've studied this before and I know the subject. Happy coding!
Several years ago I took an algorithms course where we were giving the following problem (or one like it):
There is a building of n floors with an elevator that can only go up 2 floors at a time and down 3 floors at a time. Using dynamic programming write a function that will compute the number of steps it takes the elevator to get from floor i to floor j.
This is obviously easy using a stateful approach, you create an array n elements long and fill it up with the values. You could even use a technically non-stateful approach that involves accumulating a result as recursively passing it around. My question is how to do this in a non-stateful manner by using lazy evaluation and tying the knot.
I think I've devised the correct mathematical formula:
where i+2 and i-3 are within the allowed values.
Unfortunately I can't get it to terminate. If I put the i+2 case first and then choose an even floor I can get it to evaluate the even floors below the target level but that's it. I suspect that it shoots straight to the highest even floor for everything else, drops 3 levels, then repeats, forever oscillating between the top few floors.
So it's probably exploring the infinite space (or finite but with loops) in a depth first manner. I can't think of how to explore the space in a breadth first fashion without using a whole lot of data structures in between that effectively mimic a stateful approach.
Although this simple problem is disappointingly difficult I suspect that having seen a solution in 1 dimension I might be able to make it work for a 2 dimensional variation of the problem.
EDIT: A lot of the answers tried to solve the problem in a different way. The problem itself isn't interesting to me, the question is about the method used. Chaosmatter's approach of creating a minimal function which can compare potentially infinite numbers is possibly a step in the right direction. Unfortunately if I try to create a list representing a building with 100 floors the result takes too long to compute, since the solutions to sub problems are not reused.
I made an attempt to use a self-referencing data structure but it doesn't terminate, there is some kind of infinite loop going on. I'll post my code so you can understand what it is I'm going for. I'll change the accepted answer if someone can actually solve the problem using dynamic programming on a self-referential data structure using laziness to avoid computing things more than once.
levels = go [0..10]
where
go [] = []
go (x:xs) = minimum
[ if i == 7
then 0
else 1 + levels !! i
| i <- filter (\n -> n >= 0 && n <= 10) [x+2,x-3] ]
: go xs
You can see how 1 + levels !! i tries to reference the previously calculated result and how filter (\n -> n >= 0 && n <= 10) [x+2,x-3] tries to limit the values of i to valid ones. As I said, this doesn't actually work, it simply demonstrates the method by which I want to see this problem solved. Other ways of solving it are not interesting to me.
Since you're trying to solve this in two dimensions, and for other problems than the one described, let's explore some more general solutions. We are trying to solve the shortest path problem on directed graphs.
Our representation of a graph is currently something like a -> [a], where the function returns the vertices reachable from the input. Any implementation will additionally require that we can compare to see if two vertices are the same, so we'll need Eq a.
The following graph is problematic, and introduces almost all of the difficulty in solving the problem in general:
problematic 1 = [2]
problematic 2 = [3]
problematic 3 = [2]
problematic 4 = []
When trying to reach 4 from 1, there are is a cycle involving 2 and 3 that must be detected to determine that there is no path from 1 to 4.
Breadth-first search
The algorithm Will presented has, if applied to the general problem for finite graphs, worst case performance that is unbounded in both time and space. We can modify his solution to attack the general problem for graphs containing only finite paths and finite cycles by adding cycle detection. Both his original solution and this modification will find finite paths even in infinite graphs, but neither is able to reliably determine that there is no path between two vertices in an infinite graph.
acyclicPaths :: (Eq a) => (a->[a]) -> a -> a -> [[a]]
acyclicPaths steps i j = map (tail . reverse) . filter ((== j).head) $ queue
where
queue = [[i]] ++ gen 1 queue
gen d _ | d <= 0 = []
gen d (visited:t) = let r = filter ((flip notElem) visited) . steps . head $ visited
in map (:visited) r ++ gen (d+length r-1) t
shortestPath :: (Eq a) => (a->[a]) -> a -> a -> Maybe [a]
shortestPath succs i j = listToMaybe (acyclicPaths succs i j)
Reusing the step function from Will's answer as the definition of your example problem, we could get the length of the shortest path from floor 4 to 5 of an 11 story building by fmap length $ shortestPath (step 11) 4 5. This returns Just 3.
Let's consider a finite graph with v vertices and e edges. A graph with v vertices and e edges can be described by an input of size n ~ O(v+e). The worst case graph for this algorithm is to have one unreachable vertex, j, and the remaining vertexes and edges devoted to creating the largest number of acyclic paths starting at i. This is probably something like a clique containing all the vertices that aren't i or j, with edges from i to every other vertex that isn't j. The number of vertices in a clique with e edges is O(e^(1/2)), so this graph has e ~ O(n), v ~ O(n^(1/2)). This graph would have O((n^(1/2))!) paths to explore before determining that j is unreachable.
The memory required by this function for this case is O((n^(1/2))!), since it only requires a constant increase in the queue for each path.
The time required by this function for this case is O((n^(1/2))! * n^(1/2)). Each time it expands a path, it must check that the new node isn't already in the path, which takes O(v) ~ O(n^(1/2)) time. This could be improved to O(log (n^(1/2))) if we had Ord a and used a Set a or similar structure to store the visited vertices.
For non-finite graphs, this function should only fail to terminate exactly when there doesn't exists a finite path from i to j but there does exist a non-finite path from i to j.
Dynamic Programming
A dynamic programming solution doesn't generalize in the same way; let's explore why.
To start with, we'll adapt chaosmasttter's solution to have the same interface as our breadth-first search solution:
instance Show Natural where
show = show . toNum
infinity = Next infinity
shortestPath' :: (Eq a) => (a->[a]) -> a -> a -> Natural
shortestPath' steps i j = go i
where
go i | i == j = Zero
| otherwise = Next . foldr minimal infinity . map go . steps $ i
This works nicely for the elevator problem, shortestPath' (step 11) 4 5 is 3. Unfortunately, for our problematic problem, shortestPath' problematic 1 4 overflows the stack. If we add a bit more code for Natural numbers:
fromInt :: Int -> Natural
fromInt x = (iterate Next Zero) !! x
instance Eq Natural where
Zero == Zero = True
(Next a) == (Next b) = a == b
_ == _ = False
instance Ord Natural where
compare Zero Zero = EQ
compare Zero _ = LT
compare _ Zero = GT
compare (Next a) (Next b) = compare a b
we can ask if the shortest path is shorter than some upper bound. In my opinion, this really shows off what's happening with lazy evaluation. problematic 1 4 < fromInt 100 is False and problematic 1 4 > fromInt 100 is True.
Next, to explore dynamic programming, we'll need to introduce some dynamic programming. Since we will build a table of the solutions to all of the sub-problems, we will need to know the possible values that the vertices can take. This gives us a slightly different interface:
shortestPath'' :: (Ix a) => (a->[a]) -> (a, a) -> a -> a -> Natural
shortestPath'' steps bounds i j = go i
where
go i = lookupTable ! i
lookupTable = buildTable bounds go2
go2 i | i == j = Zero
| otherwise = Next . foldr minimal infinity . map go . steps $ i
-- A utility function that makes memoizing things easier
buildTable :: (Ix i) => (i, i) -> (i -> e) -> Array i e
buildTable bounds f = array bounds . map (\x -> (x, f x)) $ range bounds
We can use this like shortestPath'' (step 11) (1,11) 4 5 or shortestPath'' problematic (1,4) 1 4 < fromInt 100. This still can't detect cycles...
Dynamic programming and cycle detection
The cycle detection is problematic for dynamic programming, because the sub-problems aren't the same when they are approached from different paths. Consider a variant of our problematic problem.
problematic' 1 = [2, 3]
problematic' 2 = [3]
problematic' 3 = [2]
problematic' 4 = []
If we are trying to get from 1 to 4, we have two options:
go to 2 and take the shortest path from 2 to 4
go to 3 and take the shortest path from 3 to 4
If we choose to explore 2, we will be faced with the following option:
go to 3 and take the shortest path from 3 to 4
We want to combine the two explorations of the shortest path from 3 to 4 into the same entry in the table. If we want to avoid cycles, this is really something slightly more subtle. The problems we faced were really:
go to 2 and take the shortest path from 2 to 4 that doesn't visit 1
go to 3 and take the shortest path from 3 to 4 that doesn't visit 1
After choosing 2
go to 3 and take the shortest path from 3 to 4 that doesn't visit 1 or 2
These two questions about how to get from 3 to 4 have two slightly different answers. They are two different sub-problems which can't fit in the same spot in a table. Answering the first question eventually requires determining that you can't get to 4 from 2. Answering the second question is straightforward.
We could make a bunch of tables for each possible set of previously visited vertices, but that doesn't sound very efficient. I've almost convinced myself that we can't do reach-ability as a dynamic programming problem using only laziness.
Breadth-first search redux
While working on a dynamic programming solution with reach-ability or cycle detection, I realized that once we have seen a node in the options, no later path visiting that node can ever be optimal, whether or not we follow that node. If we reconsider problematic':
If we are trying to get from 1 to 4, we have two options:
go to 2 and take the shortest path from 2 to 4 without visiting 1, 2, or 3
go to 3 and take the shortest path from 3 to 4 without visiting 1, 2, or 3
This gives us an algorithm to find the length of the shortest path quite easily:
-- Vertices first reachable in each generation
generations :: (Ord a) => (a->[a]) -> a -> [Set.Set a]
generations steps i = takeWhile (not . Set.null) $ Set.singleton i: go (Set.singleton i) (Set.singleton i)
where go seen previouslyNovel = let reachable = Set.fromList (Set.toList previouslyNovel >>= steps)
novel = reachable `Set.difference` seen
nowSeen = reachable `Set.union` seen
in novel:go nowSeen novel
lengthShortestPath :: (Ord a) => (a->[a]) -> a -> a -> Maybe Int
lengthShortestPath steps i j = findIndex (Set.member j) $ generations steps i
As expected, lengthShortestPath (step 11) 4 5 is Just 3 and lengthShortestPath problematic 1 4 is Nothing.
In the worst case, generations requires space that is O(v*log v), and time that is O(v*e*log v).
The problem is that min needs to fully evaluate both calls to f,
so if one of them loops infinitly min will never return.
So you have to create a new type, encoding that the number returned by f is Zero or a Successor of Zero.
data Natural = Next Natural
| Zero
toNum :: Num n => Natural -> n
toNum Zero = 0
toNum (Next n) = 1 + (toNum n)
minimal :: Natural -> Natural -> Natural
minimal Zero _ = Zero
minimal _ Zero = Zero
minimal (Next a) (Next b) = Next $ minimal a b
f i j | i == j = Zero
| otherwise = Next $ minimal (f l j) (f r j)
where l = i + 2
r = i - 3
This code actually works.
standing on the floor i of n-story building, find minimal number of steps it takes to get to the floor j, where
step n i = [i-3 | i-3 > 0] ++ [i+2 | i+2 <= n]
thus we have a tree. we need to search it in breadth-first fashion until we get a node holding the value j. its depth is the number of steps. we build a queue, carrying the depth levels,
solution n i j = case dropWhile ((/= j).snd) queue
of [] -> Nothing
((k,_):_) -> Just k
where
queue = [(0,i)] ++ gen 1 queue
The function gen d p takes its input p from d notches back from its production point along the output queue:
gen d _ | d <= 0 = []
gen d ((k,i1):t) = let r = step n i1
in map (k+1 ,) r ++ gen (d+length r-1) t
Uses TupleSections. There's no knot tying here, just corecursion, i.e. (optimistic) forward production and frugal exploration. Works fine without knot tying because we only look for the first solution. If we were searching for several of them, then we'd need to eliminate the cycles somehow.
see also: https://en.wikipedia.org/wiki/Corecursion#Discussion
With the cycle detection:
solutionCD1 n i j = case dropWhile ((/= j).snd) queue
of [] -> Nothing
((k,_):_) -> Just k
where
step n i visited = [i2 | let i2=i-3, not $ elem i2 visited, i2 > 0]
++ [i2 | let i2=i+2, not $ elem i2 visited, i2 <=n]
queue = [(0,i)] ++ gen 1 queue [i]
gen d _ _ | d <= 0 = []
gen d ((k,i1):t) visited = let r = step n i1 visited
in map (k+1 ,) r ++
gen (d+length r-1) t (r++visited)
e.g. solution CD1 100 100 7 runs instantly, producing Just 31. The visited list is pretty much a copy of the instantiated prefix of the queue itself. It could be maintained as a Map, to improve time complexity (as it is, sol 10000 10000 7 => Just 3331 takes 1.27 secs on Ideone).
Some explanations seem to be in order.
First, there's nothing 2D about your problem, because the target floor j is fixed.
What you seem to want is memoization, as your latest edit indicates. Memoization is useful for recursive solutions; your function is indeed recursive - analyzing its argument into sub-cases, synthetizing its result from results of calling itself on sub-cases (here, i+2 and i-3) which are closer to the base case (here, i==j).
Because arithmetics is strict, your formula is divergent in the presence of any infinite path in the tree of steps (going from floor to floor). The answer by chaosmasttter, by using lazy arithmetics instead, turns it automagically into a breadth-first search algorithm which is divergent only if there's no finite paths in the tree, exactly like my first solution above (save for the fact that it's not checking for out-of-bounds indices). But it is still recursive, so indeed memoization is called for.
The usual way to approach it first, is to introduce sharing by "going through a list" (inefficient, because of sequential access; for efficient memoization solutions see hackage):
f n i j = g i
where
gs = map g [0..n] -- floors 1,...,n (0 is unused)
g i | i == j = Zero
| r > n = Next (gs !! l) -- assuming there's enough floors in the building
| l < 1 = Next (gs !! r)
| otherwise = Next $ minimal (gs !! l) (gs !! r)
where r = i + 2
l = i - 3
not tested.
My solution is corecursive. It needs no memoization (just needs to be careful with the duplicates), because it is generative, like the dynamic programming is too. It proceeds away from its starting case, i.e. the starting floor. An external accessor chooses the appropriate generated result.
It does tie a knot - it defines queue by using it - queue is on both sides of the equation. I consider it the simpler case of knot tying, because it is just about accessing the previously generated values, in disguise.
The knot tying of the 2nd kind, the more complicated one, is usually about putting some yet-undefined value in some data structure and returning it to be defined by some later portion of the code (like e.g. a back-link pointer in doubly-linked circular list); this is indeed not what my1 code is doing. What it does do is generating a queue, adding at its end and "removing" from its front; in the end it's just a difference list technique of Prolog, the open-ended list with its end pointer maintained and updated, the top-down list building of tail recursion modulo cons - all the same things conceptually. First described (though not named) in 1974, AFAIK.
1 based entirely on the code from Wikipedia.
Others have answered your direct question about dynamic programming. However, for this kind of problem I think the greedy approach works the best. It's implementation is very straightforward.
f i j :: Int -> Int -> Int
f i j = snd $ until (\(i,_) -> i == j)
(\(i,x) -> (i + if i < j then 2 else (-3),x+1))
(i,0)
I'm trying to solve following DP problem:
You have 4 types of lego blocks, of sizes 1 * 1 * 1, 1 * 1 * 2, 1 * 1
* 3 and 1 * 1 * 4. Assume you have infinite number of blocks of each type.
You want to make a wall of height H and width M out of these blocks.
The wall should not have any holes in it. The wall you build should be
one solid structure. A solid structure means that it should not be
possible to separate the wall along any vertical line without cutting
any lego block used to build the wall. The blocks can only be placed
horizontally. In how many ways can the wall be built?
Here is how I'm attempting it:
Representing 1 * 1 * 1, 1 * 1 * 2, 1 * 1 * 3 and 1 * 1 * 4 blocks with a b c d
. Valid patterns are indicated in bold. Invalid patterns are which can be broken by vertical line.
H=1 & W=3 #valid pattern=1 aa ab ba c
H=2 & W=3 #valid pattern=9
I'm trying to find recurrence pattern either to extend this by height or width.i.e to find values for H=3 & W=3 or H=2&W=4.
Any inputs on how to formula-ize growth for this by height or weight?
P.S. The wall be always H*W*1.
First, let's see how many M*N walls can we build if we neglect the need to keep them connected:
We can treat each row separately, and then multiply the counts since they are independent.
There is only one way to tile a 0*1 or a 1*1 wall, and the number of ways to tile an n*1 is the total of the number of ways to tile {n-1}*1...{n-4}*1-sized walls, the reason being these walls can be obtained by removing the last tile of the n*1 wall.
This gives rise to a tetranacci sequence, OEIS A000078.
The number of all W*H walls is a(w,h)=T(w)^h.
Now, to count the number of solid walls. MBo's answer already contains the basic premise:
Branch on the leftmost place where the wall is not connected. The number of All W*H walls is the number of Solid X*H walls times the number of All {W-X}*H walls, summed across all possible values of X, plus the number of Solid W*H walls:
A(W,H) = sum{X=1..{W-1}}(S(X,H)*A(W-X,H)) + S(W,H)
As a last step, we separate S(M,H) term, which is the value we want to calculate, and repeat the previous formulas:
S(W,H) = A(W,H) - sum_x( S(X,H)*A(W-X,H) ) //implicitly, S(1,H)=1
A(W,H) = T(W)^H
T(X) = X > 0: T(X-1)+T(X-2)+T(X-3)+T(X-4)
X = 0: 1
X < 0: 0
(proving MBo's formula correct).
This also provides an O(W^2) algorithm to compute S (assuming proper memoization and constant-time arithmetic operations)
It is not hard to find a number of 1xW stripes (let it is N(1,W)).
Then you can find a number of all (including non-solid) HxW walls - it is A(H,W) = N(1,W)^H
Any non-solid wall consists of left H*L wall and right H*(W-L) wall. It seems that number of solid walls is
S(H,W) = A(H,W) - Sum(S(H, L) * A(H, W-L)) [L=1..W-1]
S(H, L) * A(H, W-L) is number of non-solid walls with the leftmost break at L vertical position. First factor is the number of solid walls - to eliminate counting of repetitive variants.
My Python 3 implementation
def tetranacci(n):
arr = [1, 2, 4, 8]
if n <= 4:
return arr[:n]
else:
for i in range(4, n):
arr.append(sum(arr[i-4:i])%(10**9 + 7))
return arr
def legoBlocks(n, m):
MOD = (10**9 +7)
a, s = [(v**n)%MOD for v in tetranacci(m)], [1]
for i in range(1, len(a)):
sums = sum([x*y for x,y in zip(a[:i], s[::-1])])
s.append( (a[i]-sums)%MOD)
return s[-1]