1

I have a two-dimensional map of land and water, like the following (l representing land and w representing water).

lllwwwlll
lllwllllw
lllllllww
lllllllll

For each land tile, I want to know its distance from the nearest water tile. Moving horizontally, vertically, and diagonally all count as a distance of one.

321www111
321w1111w
3211121ww
322222111

Right now I am using an algorithm like so:

foreach tile in map
  if isWater(tile)
    tile.distanceFromWater = 0
  else
    radius = 1
    while !hasWaterAround(tile, radius)
      radius++
    tile.distanceFromWater = radius

This approach works, but it rather slow, especially when there are very few water tiles.

Is there a faster algorithm for finding the distance of each land tile from water?

Peter Olson
  • 139,199
  • 49
  • 202
  • 242

2 Answers2

2

We can do something like the following (similar to BFS, but starting possibly with multiple sources):

Have a queue (FIFO) initially empty. Have another mxn grid D of distances with all elements initialized to infinity.

  1. Traverse all the tiles and push (the positions of) the water tiles in the queue (this will take O(mn) if the grid is mxn). Also, have D[pos] <- 0 for all water tile positions.
  2. While queue is not empty do the following: 2.1. Pop a tile t from the queue. 2.2. Check all the adjacent tiles t_a (left, right, top, bottom, diagonal, also accounting for the corner cases, should be found in O(1) time), and check if D[t_a] > D[t] + 1 then D[t_a] <- D[t] + 1 and push t_a onto the queue.

Step 2 should not take more than O(mn) time for a mxn grid.

Sandipan Dey
  • 21,482
  • 2
  • 51
  • 63
  • Upvoted, but step 2 can be simpler I think. One need only check if D[t_a] is infinity -- it is guaranteed given the BFS nature of the algorithm that the first assignment to a distance will be the smallest. – Paul Hankin Jan 31 '17 at 19:09
  • Yeah but even in that case we need the if block (check if != infinity instead of the current check), so from time complexity point of view it will remain the same i guess. – Sandipan Dey Jan 31 '17 at 19:24
  • Yes, but it makes it simpler to understand the algorithm because as written it appears that each D can be updated multiple times. – Paul Hankin Jan 31 '17 at 20:53
1

Do a breadth-first-search over all the tiles in the map, starting with the water tiles as roots and following edges to neighboring tiles. The level at which you you find a tile will be its distance from water.

See this answer for a nice way to keep track of the depth during BFS:

How to keep track of BFS depth in C++

Community
  • 1
  • 1
Matt Timmermans
  • 53,709
  • 3
  • 46
  • 87