Related
You are provided with an N*M matrix containing Integer values. Your task is to select one integer from each row such that the sum of these integers is maximum. However, you are not allowed to select two integers from adjacent rows in the same column.
How can I do this problem in less than O(N^M) (or O(M^N))?
I came up with two possible solutions: 1. using recursion, 2. using DP.
1. Using Recursion
I think you already have this solution. I made a recursive function that goes through each row in matrix and calls recursion for each column. As you mentioned, the time complexity would be O(M^N) where N is the number of rows and M is the number of columns.
int getMaxSum(int[][] matrix) {
return getMax(matrix, 0, -1);
}
int getMax(int[][] matrix, int row, int prevCol) {
if (row >= matrix.length) return 0;
int result = Integer.MIN_VALUE;
for (int i = 0; i < matrix[row].length; i++) {
if (i == prevCol) continue;
int sum = getMax(matrix, row+1, i) + matrix[row][i];
result = Math.max(result, sum);
}
return result;
}
2. Using DP
Instead of recursively going through all rows and columns, I can use DP to keep track of maximum sum for each column up to a certain row. For example, DP[r][c] can have a maximum possible sum at column c up to row r. To implement this, I need to go through all rows and columns in the input matrix, and at each index, I also need to go through maximum possible sums at previous row (excluding the same column). This would result in time complexity of O(N*M^2) where N is the number of rows and M is the number of columns.
int getMaxSum(int[][] matrix) {
if (matrix.length == 0) return 0;
int[][] maxSumsDP = new int[matrix.length+1][matrix[0].length];
for (int r = 1; r <= matrix.length; r++) {
for (int c = 0; c < matrix[r-1].length; c++) {
int maxPrev = Integer.MIN_VALUE;
for (int i = 0; i < maxSumDP[r-1].length; i++) {
if (i == c) continue;
maxPrev = Math.max(maxPrev, maxSumsDP[r-1][i]);
}
maxSumsDP[r][c] = maxPrev + matrix[r-1][c];
}
}
int result = maxSumsDP[maxSumsDP.length-1][0];
for (int i = 1; i < maxSumsDP[maxSumsDP.length-1].length; i++) {
result = Math.max(result, maxSumsDP[maxSumsDP.length-1][i]);
}
return result;
}
I'm looking for an algorithm which can explore a whole grid, excluding adjacent cells.
The picture is showing green blob where I am, and blue blobs what I can see. Now I want to visit every cell on the grid ("see" every cell). Which means I want to move in such a way that I don't have to move to every cell, skipping adjacent cells.
Is there a name for an algorithm like that or what can be recommended here? Please note, the grid can be any size any number of cells, the constraints remain the same: I can always "see" adjacent cells.
I guess the closest term is padding/stride?
In your case you pad 1, and stride 3.
for(var i = 1; i<n; i+=3){
for(var j = 1; j<m; j+=3){
//visit your cell
}
}
There may arise a problem if you don't have a multiple of 3 rows/columns.
Consider the cases (grid width is not the same) when you iterate to the right. x is a cell. O is a cell you will visit with above for loop
...xxxxxx
...xOxxOx <-- ok you can see everything
...xxxxxx
...xxxxx
...xOxxO <-- ok you can see everything
...xxxxx
...xxxx
...xOxxF <-- ko you are out of bounds and should have taken the "first" column
...xxxx
The ko case appear when grid.width%3 = 1
so you may handle it separately
for(var i = 1; i<n; i+=3){
for(var j = 1; j<m; j+=3){
//visitCell(i,j)
}
}
if(n%3 == 1){
for(var j = 1; j<m; j+=3){
visitCell(n-1,j);
}
}
if(m%3 == 1){
for(var i = 1; i<n; i+=3){
visitCell(i,m-1);
}
}
if(m%3 == 1 && n%3 == 1){
visitCell(n-1,m-1);
}
fiddle: https://jsfiddle.net/khvsz4fx/
I have an assignment to solve using dynamic programming the following problem:
There is a rectangular sheet and a set of rectangular elements of given dimensions and value. The task is to divide the sheet into elements of given dimensions, so that the sum of values of the elements is maximum. Find this sum and a tree of consequent cuts.
There are following conditions:
It is NOT possible to rotate the given elements.
It is possible to cut out unlimited number of certain types of
elements.
It is possible that some parts of the sheet will remain unused.
The only possible way to cut the sheet is by a straight
line, so that you again obtain two smaller rectangles.
The problem is solved. Solution can be found below.
==========================================================================
I understand the problem for one dimension, which comes to the rod cutting problem. You divide the rod into the smallest possible pieces, take the first one and check if you can build it with the given segments. Remember the weight you'll get with building the part this way and move on to a bigger part containing the previous one. You go back by the length of the segment you're trying at the moment and check if using this segment plus the weight of the previously build part will make up to better sum of the weight for the current part.
Supposedly, the cutting wood problem is no different, but you add the 2-dimension, additional loop somewhere in the middle. Unfortunately, I can't imagine how to store the values and how to go back for the 2-dimensions.
I've tried doing like:
1. Loop on one dimension
2. Loop on second dimension
3. Loop on all the segments you can use
4. Check if you can fit the current segment depending on 1. and 2.
5. If yes, go back the length of the segment to see if weight of the segment + what's stored there gives you a greater result; do the same for the width
6. Store the result in the cell you're currently on
7. Go through the array and find the greatest result
Here is the code I produced after many debugging tries:
public int Cut((int length, int width) sheet, (int length, int width, int price)[] elements, out Cut cuts)
{
int[,] tmpSheetArr = new int[sheet.length + 1, sheet.width + 1];
for (int i = 1; i < tmpSheetArr.GetLength(0); i++)
{
for (int j = 1; j < tmpSheetArr.GetLength(1); j++)
{
tmpSheetArr[i, j] = Int32.MinValue;
}
}
for (int i = 1; i < tmpSheetArr.GetLength(0); i++) //columns
{
for (int j = 1; j < tmpSheetArr.GetLength(1); j++) //rows
{
for (int e = 0; e < elements.Length; e++)
{
(int length, int width, int price) elem = elements[e];
if (i >= elem.length && j >= elem.width)
{
int tmpJ, tmpI, tmpVal;
tmpJ = j - elem.width;
tmpI = i;
while (0 < tmpI)
{
if(tmpI > i - elem.length && tmpI <= i && tmpJ > j - elem.width && tmpJ <= j)
{
tmpJ -= 1;
if (-1 == tmpJ)
{
tmpJ = tmpSheetArr.GetLength(1) - 1;
tmpI -= 1;
}
continue;
}
tmpVal = tmpSheetArr[tmpI, tmpJ] == Int32.MinValue ? 0 : tmpSheetArr[tmpI, tmpJ];
if (tmpSheetArr[i, j] < elem.price + tmpVal)
{
tmpSheetArr[i, j] = elem.price + tmpVal;
}
tmpJ -= 1;
if(-1 == tmpJ)
{
tmpJ = tmpSheetArr.GetLength(1) - 1;
tmpI -= 1;
}
}
}
}
}
}
int tmpMax = 0;
for (int i = 1; i < tmpSheetArr.GetLength(0); i++)
{
for (int j = 1; j < tmpSheetArr.GetLength(1); j++)
{
if (tmpMax < tmpSheetArr[i, j])
tmpMax = tmpSheetArr[i, j];
}
}
cuts = null;
return tmpMax;
}
It doesn't work, gives too big results in some cases and gets stuck on bigger problems. I think the main problem is about going back - with only the weight stored I don't know what size of the block was used and if it will overlap with the current one.
I decided to write it from the beginning, but really can't find another approach. I have a code for the 1D problem:
int cutRod(int[] price, int n)
{
int[] val = new int[n + 1];
val[0] = 0;
int i, j;
// Build the table val[] and return the last entry
// from the table
for (i = 1; i <= n; i++)
{
int max_val = Int32.MinValue;
for (j = 0; j < i; j++)
max_val = Math.Max(max_val, price[j] + val[i - j - 1]);
val[i] = max_val;
}
return val[n];
}
How do I change it so it works for 2D problem?
I tried to explain my limited understanding and way of thinking the best I could. I would appreciate any help on this matter.
Make your dynamic state at x be a dictionary mapping a particular "skyline" of what blocks placed before x look like after x. You start with a flat skyline (no blocks so far, clean edge), and you're looking for a flat skyline at the other end (didn't go off the edge of the sheet).
As you advance you "lower" your skyline by 1, start looking at ways to cut out new blocks, and get new possible skylines.
The number of possible skylines will grow exponentially with the width of the rectangle.
The solution:
Build an array of maximum values that can be obtained from given piece of dimensions 1x1 up to the size of the board. Maximum value for given piece is stored under index of [(length of the piece) - 1, (width of the piece) - 1]. To find the maximum value, check how the current piece can be formed with previous pieces and cuts.
To construct the tree of cuts, build a second array of the best cuts for the current piece. Root of the cuts tree for the current piece is stored under index of [(length of the piece) - 1, (width of the piece) - 1].
Cuts class:
public class Cut
{
public int length; // vertical dimension (before cut)
public int width; // horizontal dimension (before cut)
public int price; // sum of the values of the two elements resulting from the cut
public bool vertical; // true for vertical cut, false otherwise
public int n; // distance from left side (for vertical cut) or top (for horizontal cut) of the current piece
// price 0 means there was no cut, topleft and bottomright are null,
public Cut topleft; // top/left resulting piece after cut
public Cut bottomright; // bottom/right resulting piece after cut
public Cut(int length, int width, int price, bool vertical=true, int n=0, Cut topleft=null, Cut bottomright=null)
{
this.length = length;
this.width = width;
this.price = price;
this.vertical = vertical;
this.n = n;
this.topleft = topleft;
this.bottomright = bottomright;
}
}
Function finding the maximum value and a tree of cuts:
public int Cut((int length, int width) sheet, (int length, int width, int price)[] elements, out Cut cuts)
{
int[,] sheetArr = new int[sheet.length, sheet.width]; //contains best values of current pieces that can be formed
Cut[,] cutsArr = new Cut[sheet.length, sheet.width]; //contains references for cuts used to form pieces of the best value,
for (int l = 0; l < sheet.length; l++) //loop on length
{
for (int w = 0; w < sheet.width; w++) //loop on width
{
foreach ((int length, int width, int price) elem in elements) //loop on elements
{
if (elem.length == l + 1 && elem.width == w + 1) //check if current piece can be build with one of the given elements
{
sheetArr[l, w] = elem.price;
cutsArr[l, w] = new Cut(elem.length, elem.width, elem.price); //piece is exactly one of the elements (no cut)
break; //no 2 elements of the same size in the given elements
}
cutsArr[l, w] = new Cut(l + 1, w + 1, 0); //piece can not be formed from given elements, price = 0 (no cut)
}
for (int i = 1; i < Math.Floor((decimal)(l + 1) / 2) + 1; i++) //go back on length
{
if (sheetArr[i - 1, w] + sheetArr[l - i, w] > sheetArr[l, w])
{
sheetArr[l, w] = sheetArr[i - 1, w] + sheetArr[l - i, w];
cutsArr[l, w] = new Cut(l + 1, w + 1, sheetArr[l, w], false, i, cutsArr[i - 1, w], cutsArr[l - i, w]);
}
}
for (int i = 1; i < Math.Floor((decimal)(w + 1) / 2) + 1; i++) //go back on width
{
if (sheetArr[l, i - 1] + sheetArr[l, w - i] > sheetArr[l, w])
{
sheetArr[l, w] = sheetArr[l, i - 1] + sheetArr[l, w - i];
cutsArr[l, w] = new Cut(l + 1, w + 1, sheetArr[l, w], true, i, cutsArr[l, i - 1], cutsArr[l, w - i]);
}
}
}
}
cuts = cutsArr[sheet.length - 1, sheet.width - 1];
return sheetArr[sheet.length - 1, sheet.width - 1];
}
Given an m x n matrix of 0s and 1s, if an element is 0, set its entire row and column to 0
How can we solve this problem without any extra space complexity
Use first row and first column as list of flags for marking corresponding column and row respectively. So in total, there would be m+n-1 flags available to you for mxn matrix, only one extra flag would be needed to mark 1st row or 1st column (its upon programmer to choose, doesn't make difference though).
[C0/R0] C1 C2 ... Cn-1
R1
R2
.
Rm-1
Take one extra flag for [R0/C0].
Then traverse through the matrix, marking the flags if any of element in the column or row is 0.
Then once you finish traversing, use those flags to decide which column or row would be filled with all 0's.
A naive approach would be to simply iterate the whole matrix:
for i in 1 to number of rows
for j in 1 to number of columns
if n(i,j) == 0:
for all n(i, 1 to number of columns): set to 0
for all n(1 to number of rows, j): set to 0
This doesn't require any additional space besides the the two loop counters. Of course, it is O(scary) regarding performance, but you didn't ask about that.
In order to enhance performance, you could collect all row and column indexes that contain 1; and zero-ize them just once; but that would mean: allocating space for those indexes.
Reduce the space used to O(1) by using boolean variables (and not boolean array)
check if first row & column are zero. If yes, set the corresponding boolean variables: rowZero and colZero
iterate through the remaining rows & columns and mark them as zero wherever applicable
if the first row/column is not zero, then use the methods to mark them as zero
public static void ZeroMatrixResultBitVector(int[][] matrix)
{
bool rowZero = false;
bool colZero = false;
// check if first row has zero
for (int i = 0; i < matrix.Length; i++)
{
if (matrix[i][0] == 0)
{
colZero = true;
break;
}
}
// check if first column is zero
for (int j = 0; j < matrix[0].Length; j++)
{
if (matrix[0][j] == 0)
{
rowZero = true;
break;
}
}
//if the above hasn't been true then we will update the first column/row later
for (int i = 1; i < matrix.Length; i++)
{
for (int j = 1; j < matrix[0].Length; j++)
{
if (matrix[i][j] == 0)
{
matrix[i][0] = 0;
matrix[0][j] = 0;
}
}
}
//nullify all row related records
for (int i = 1; i < matrix.Length; i++)
{
if (matrix[i][0] == 0)
{
nullifyRow(matrix, i);
}
}
//nullify all column related records
for (int j = 1; j < matrix[0].Length; j++)
{
if (matrix[0][j] == 0)
{
nullifyColumn(matrix, j);
}
}
if (rowZero)
{
nullifyRow(matrix, 0);
}
if (colZero)
{
nullifyColumn(matrix, 0);
}
}
Function to nullify Rows:
private static void nullifyRow(int[][] matrix, int row)
{
for (int j = 0; j < matrix[0].Length; j++)
{
matrix[row][j] = 0;
}
}
Function to nullify column:
private static void nullifyColumn(int[][] matrix, int column)
{
for (int i = 0; i < matrix[0].Length; i++)
{
matrix[i][column] = 0;
}
}
Algorithm
Consider this layout:
+-------------+
| |
| |
| +--+ |
| |##| |
| |##| |
| +--+------+
| |######|
| |######|
+------+------+
The black part is the occupied space. Now I need an algorithm that returns the largest remaining rectangular spaces. (Ordered from top to bottom, left to right.)
Like this:
1 2 3 4
+-------------+ +---- -------+
|#############| |### ######|
|#############| |### ######|
| +--+ | |###+ +######|
|###| |######|
|###| |######|
|###+ +------| | +--+
|### |######|
|### |######|
+---- +------+
Input
The width and height of the enclosing container. (A page in my code.)
A list of already occupied rectangles. They can be in any form that you like. E.g. (x,y,width,height) or (x1,y1,x2,y2)
I'm dealing with floats, therefore a mathematical solution would be preferred.
From your example it appears that you aren't asking to exclude overlap (e.g. 1 and 2 have the top-left segment in common), so perhaps this will suit your needs:
Divide the space into rectangles based on the corners identified by the occupied spaces.
Form the "basic rectangles" by extending line segments from those corners to the edges of the entire space.
Using any systematic order (e.g. top-to-bottom, left-to-right):
3.1. Select a basic rectangle and extend it as far as possible with other basic rectangles that have a side in common.
3.2. Form the set of all (unique) such extended rectangles.
Note that this searches/builds based on the "basic rectangles" from step 2, and not point-by-point throughout the entire space, so the performance should be much better.
Pardon me for writing in codes:
for(int y = 0; y < rows; y++){
for(int x = 0; x < columns; x++){
// (x, y) would be the current space
if(checkEmptySpace(x,y)){
// empty space found
}
}
}
That's the easiest and straight way to do this. but the bad point is that it has to loop through all the space which may cause inefficiency.
Improvised:
(STEP1) loop through all the rows while rows are empty
(STEP1) stop when an occupied space is found in the row
(STEP1) store the value of the current row to TOP_EMPTY only when first time
(STEP2) if number remaining rows is > number of columns go to step 8
(STEP2) loop through remaining rows
(STEP2) calculate space in front of occupied space
(STEP2) calculate space behind occupied space
(STEP2) loop end
(STEP2) go to 13
(STEP2) loop through columns
(STEP2) skip TOP_EMPTY rows
(STEP2) calculate space before occupied space in column
(STEP2) calculate space after occupied space in column
(STEP2) loop end
(STEP3) calculate the space at the top with TOP_EMPTY * no. of columns
DONE.
char mark = 'A';
for(i from 0 to rows)
colstart = 0;
while(colstart = next empty col in ith row)
width = 0;
for(j from colstart to columns)
{
if(empty)
width++;
else
break;
}
if(width == 0)
continue
for(n from colstart to colstart + width)
for(m from i to rows)
if(!empty)
break;
if(m != i)
set the rectangle from i, colstart to m - 1, colstart + width
with mark char and increment mark;
update: java code.
public class Program
{
public static char occuppied;
public static char vacant;
public static char mark;
public static void main(String[] args)
{
int rows = 7;
int cols = 11;
mark = 'A';
occuppied = '#';
vacant = '-';
char[][] matrix = new char[rows][cols];
setRect(matrix, vacant, 0, 0, rows, cols);
setRect(matrix, occuppied, 3, 3, 2, 2);
setRect(matrix, occuppied, 5, 5, 2, 6);
print(matrix);
for(int i = 0; i < rows; i++)
{
int colstart = 0;
while((colstart = nextEmptyCol(matrix[i], colstart)) != -1)
{
int width = 0;
for(int j = colstart; j < cols; j++)
{
if(matrix[i][j] == vacant)
width++;
else
break;
}
if(width == 0)
continue;
int height = 1;
outer:
for(; height + i < rows; height++)
for(int n = 0; n < width; n++)
{
if(matrix[i + height][colstart + n] == occuppied)
break outer;
}
System.out.println("width = " + width + ", height = " + height);
setRect(matrix, mark, i, colstart, height, width);
print(matrix);
mark++;
}
}
}
public static void setRect(char[][] matrix, char c, int startrow, int startcol, int numrows, int numcols)
{
for(int i = 0; i < numrows; i++)
for(int j = 0; j < numcols; j++)
matrix[startrow + i][startcol + j] = c;
}
public static void print(char[][] matrix)
{
int rows = matrix.length;
int cols = matrix[0].length;
for(int i = 0; i < rows; i++)
{
for(int j = 0; j < cols; j++)
System.out.print(matrix[i][j] + " ");
System.out.println();
}
for(int i = 0; i < cols; i++)
System.out.print("==");
System.out.println();
}
public static int nextEmptyCol(char[] row, int start)
{
for(int i = start; i < row.length; i++)
if(row[i] == vacant)
return i;
return -1;
}
}
Start
set row=0, column=0
if is free space:
get largest free rectangle, starting horizontally
if not, and at the last column, and not at end, row + 1, column = 0 and goto 3
else if not at last column, column + 1 and goto 3
else end
(note that 3.1 is the same algorithm, only with free/blocked inverted, and with different coordinates)
You're looking for something similar to Code Golf: Running Water
I think that consider just conrers will not get the best math.
For example, in the image below, the "r" rect is the best match, but does not start in any corner.
+-------------+
| rrrr |
|+--+rrrr +--+|
||##|rrrr |##||
||##|rrrr |##||
||##|rrrr |##||
||##|rrrr |##||
|+--+rrrr +--+|
| rrrr |
+-------------+
Here is the algorithm I used for exactly the same case:
This will return a list of Empty Space Rectangles.
Order known-obstacles in a list from top-left to bottom-right
Create a first Empty Space Rectangle that takes the whole area that you want to check
For each obstacle (O) in order :
For each Empty space that overlaps O
Delete Empty Space Rectangle (ESR)
If ESR.left < O.left, Create New Empty Space Rectangle (NESR) with NESR.right = O.left and add it to the list of ESR the other obstacles must check for overlaps.
If ESR.right > O.right, Create New ESR, NESR.left = O.right
If ESR.bottom < O.bottom, Create New ESR, NESR.top = O.bottom
If ESR.top > O.top, Create New ESR, NESR.bottom = O.top
N.B: this is a sequence of If, not else if. Meaning that you create up to 4 new ESR for each overlap.
Explanation:
We create a single huge "Empty Space Rectangle", then we check for each known obstacle to know if it overlaps with it (it obviously does, as this rectangle covers everything).
The first obstacle will split the first Empty space rectangle into up to 4 smaller rectangles. Clamped to not overlap it.
The 2nd obstacle will then check if it overlaps any of the newly created Empty space rectangles. Each rectangle it overlaps is split further down, into up to 4 new rectangles. None of those will overlap either obstacle 1 or obstacle 2.
We keep going like that until every obstacle has been checked.
We end up with a list of Empty spaces that do not overlap any obstacles. We will definitely have overlaps though.
I think that you can implement a Montecarlo Approach.
Regards.