3

Recently, I came across this problem and I was intrigued as to whether 1) I could categorise this type of problem to a specific name or 2) what the best way to solve this problem was. It's a bit finicky so bear with me as I'll try to explain it the best I can (apologies in advance for the poor drawing).

You are given an n x n matrix which represents plots of soil. Each entry has a numeric value which represents the amount of water required to make that plot fertile. You are able to choose a specific co-ordinate about which the rain falls (with intensity I) and the area of rainfall depends on the parameter d (which is always even). Big d means more area..

Here comes the finicky part.

The rain falls in the way illustrated in the image below. The outskirt (represented by the dotted green lines) receive half the rainfall ( I/2 ) to their counterpart. So in this case, it would receive 4 mm. Hence, by deciding to pour rain about the point (3,3) there would be 7 plots of soil on the boundary (7 plots which are less than or equal to 8 / 2 = 4) and 10 plots of soil on the inner (10 plots which are less than or equal to 8) leading to 17 plots of soil in total that become fertile. enter image description here

The question asks, given the arguments for (n x n: 2d int array, d: int, I: int), what is the maximum number of plots of soil that can be made fertile?

n.b. there are no restrictions on where the co-ordinates may be i.e. it can be on the edge of the terrain.

I solved it in the following way:

Basically brute force but with some efficiency tweaks.

Efficiency tweak 1: Based on the value of d, there is a limit [d * (d / 2 + 1)] as to how many plots of soil it encompasses. If any point satisfies the max then stop searching.

Efficiency tweak 2: If the value of d is 10, for example, then the radius of that will be 5 meaning at best it will completely cover sqrt(5) by sqrt(5) inside the inner area. In other words, it will cover at most 2 x 2 completely and hence, we can start searching from the point (2, 2) instead of from (0, 0) which will unnecessarily water vacant land. Similarly, we can end searching at the diagonally opposite point which will be (n - 2, n - 2).

This solution feels non-optimal because as d and n x n get bigger, there is a lot of overlap in the land being calculated.

220284
  • 95
  • 7
  • *"What type of problem is this? Help categorise"* - Its an optimization problem. Is that what you really meant to ask? – Stephen C Feb 11 '21 at 02:48
  • By the way, you should not tag this as [java] or [kotlin] because the implementation language you (have?) used is not relevant. As far as I can see. (One of those *might* be relevant if you showed us the code, and asked a question **about** the code. But not both. Java and Kotlin are different languages.) – Stephen C Feb 11 '21 at 02:51
  • @StephenC I was hoping that it would belong to a more specific family of problems... It would also be nice if I could find problems similar to it. I used recursion for differentiating between the inner and outer levels but I've never seen a problem quite like this one. I just want to learn more about this problem I guess.. – 220284 Feb 11 '21 at 02:55
  • So, if you are expecting a different answer to the one I gave (which is by the way, a valid answer) then your question needs to be clearer and more explicit. (You may be better off asking this on https://scicomp.stackexchange.com/ or https://cs.stackexchange.com/) – Stephen C Feb 11 '21 at 03:07
  • Duly noted. Bear in mind, I asked two questions though. Also removed the tags, cheers. – 220284 Feb 11 '21 at 03:16
  • Ah ... I see the second question now. Note that "what is the best way" questions are often interpreted as "too broad" or "opinion-based". (In your case, it is probably neither ... but you might want to consider the wording to clarify what you mean by "best" . Best is subjective unless you specify criteria.) – Stephen C Feb 11 '21 at 03:28

3 Answers3

2

The brute force solution has O(n^2 * d^2) time complexity.

An effective optimization is to use a sliding window approach. Once you know the irrigation value for a given point, you can compute the value for the next adjacent point just by looking at the squares where the two regions differ. This allows you to reduce the complexity to O(n^2 * d).

Sliding window illustration

In fact, by taking advantage of the geometry of the problem, you can further optimize this approach to achieve optimal O(n^2) time complexity. (Hint: Think about moving the window diagonally.) Details are left as an exercise to the reader.

Further reading:

augurar
  • 12,081
  • 6
  • 50
  • 65
  • I'm not sure that is actually plausible because, in some cases, it makes more sense to start in the corner (where the entire area is not inside the grid). For example, imagine an n x n where top left has value 0 and everywhere else has +Infinity. Either 1) you start sufficiently far into the grid that you miss the solution or 2) you start in the corner in which case that sliding window approach doesn't work – 220284 Feb 11 '21 at 03:47
  • @220284 The fundamental idea is that as you slide the window across the grid, you only need to look at the differences from the previous window. You may need some extra logic for boundary conditions, but this shouldn't affect the asymptotic time complexity. I suggest looking at the links in my answer to get an idea of the general approach, then think about how you can apply it to the specifics of this problem. – augurar Feb 11 '21 at 04:32
1

If the boundary cells received the full rainfall amount, the problem would be a lot simpler. In such a case you could transform the problem into a sliding window 2D maximum subarray problem:

  1. For all cells, subtract the rainfall amount.
  2. Mark fertile cells as 1, and non-fertile cells as 0.
  3. Solve the sliding window 2D maximum subarray problem on the resulting binary matrix.

The fact that the region isn't rectangular and the boundary cells receive only half the rainfall makes the problem more difficult, but I would still classify this problem as a variation of the maximum subarray problem and researching algorithms in that space would be a good starting point.

wookie919
  • 3,054
  • 24
  • 32
  • Okay, any tips on traversing the coordinates? Note, if I refer to the co-ordinate (1,1) it is actually referring to a specific plot of soil in the array, as arrays don't really have the idea of 'co-ordinates' between values. I didn't add implementation details but the way I did it was I started with a set of points around the origin (0, 0) and I would translate these points as necessary based on where the point is. I found this to be really tedious and finicky. Wondering if there is a better way. Also, thanks for removing the duplicate. – 220284 Feb 11 '21 at 03:22
  • 1
    I can definitely relate to your pain around having to translate co-ordinates to corresponding array[x][y] items and vice versa. Dealing with off-by-one (or in this case off-by-half?) and such edge cases is always finicky and tedious, and I unfortunately don't know any tricks to make the process easier. – wookie919 Feb 11 '21 at 03:39
0

Let's say you have a table dp[][], where dp[i][j] = count of cells with value < I in row i of your matrix, between columns [0..j] (how to fill dp table: dp[i][j] = dp[i][j-1] + (intensity[i][j]<I)). For the first row of your given example, the dp table would read {1,2,3,4,5,5} Given a boundary point in a row, you can use this table to count the number of fertile cells in that row in O(1).

Now, as illustrated in your example, you can use a simple observation. For a given d, there are maximum (d-1)*4 boundary points. Consider the (d-1)*2 points on the left (for each left boundary point, there will be a right boundary point in the same row). For any given point x in that set, (let it's right counterpart be y), you can get the number of fertile cells (with full intensity rain) between x and y using the dp[][] table (count of fertile cells = dp[i][y]-dp[i][x], where i is the row number). Now, you also check if x and y themselves become fertile with I/2 rain or not.

Since there are N^2 points, and each point has O(d) boundary points, this approach would have O(N^2 * d) time complexity and O(N^2) space complexity

Abhinav Mathur
  • 7,791
  • 3
  • 10
  • 24
  • I'm sorry but I don't understand this post. Can you explain how you would fill out the values in the dp[][]? And given the example image, am I right in thinking the first row of the 2d array would be {1, 2, 3, 4, 5, 5} ? Also, I have no idea how we can use symmetry anywhere? – 220284 Feb 13 '21 at 00:37
  • Yes, I think I understand what you mean. Is it similar to what augurar said with the idea of only calculating the boundaries in the second time going through 2D intensity matrix (first time, creating the 2D dp array and second time just reading the values). Also, do you agree that it can be done in O(n^2) time as he states? – 220284 Feb 15 '21 at 08:33
  • 1
    @220284 I'm not sure about O(N^2), because that would be a lot of precomputation – Abhinav Mathur Feb 15 '21 at 10:21