Reputation:
How can I determine the distance between 1's in a 2D array. For example, we have a 2D array like this:
0 0 0 0
0 0 0 1
1 0 0 0
1 0 0 0
The algorithm has to output the distance from each element to the nearest 1. Like this:
2 3 2 1
1 2 1 0
0 1 2 1
0 1 2 2
How can I solve it ?
Upvotes: 5
Views: 17705
Reputation: 93
Upvotes: 0
Reputation:
Because you didn't specify the language :) here's a parallel version of the algorithm in Common Lisp:
(ql:quickload :lparallel)
(defpackage :compute-distances (:use :cl :lparallel))
(in-package :compute-distances)
(defun positions (number matrix)
(loop :for i :from 0 :below (array-dimension matrix 0)
:nconc (loop :for j :from 0 :below (array-dimension matrix 1)
:if (= number (aref matrix i j))
:collect (cons i j))))
(defun find-neighbours (point points)
(loop :with x := (car point) :and y := (cdr point)
:for point :across points
:unless (and (= x (car point)) (= y (cdr point)))
:collect (let ((width (- x (car point)))
(height (- y (cdr point))))
(sqrt (+ (* width width) (* height height))))))
(defun find-all-neighbours (number matrix)
(let* ((positions (coerce (positions number matrix) 'vector))
(*kernel* (make-kernel (length positions))))
(pmap 'vector (lambda (point) (find-neighbours point number matrix))
:parts (length positions) positions)))
(defparameter *test-matrix*
(make-array '(4 4) :initial-contents
'((0 0 0 0)
(0 0 0 1)
(1 0 0 0)
(1 0 0 0))))
(find-all-neighbours 1 *test-matrix*)
;; #((3.1622777 3.6055512) (3.1622777 1.0) (3.6055512 1.0))
Upvotes: 2
Reputation: 2004
I liked this question, so I created a page online where you can try out solving it: http://www.learneroo.com/courses/29/nodes/221
The solution code is below, based on @manu-fatto's answer. The method minArray
goes through the entire double array a few times, and each time it updates the minimum distance from each cell to a nearby 1 by picking the minimum value near it and adding 1.
import java.util.*;
class DistanceZ {
static void minArray(int[][] square){
int w = square.length;
for(int times = 0; times<w; times++){
for(int i =0; i<w; i++){
for(int j=0;j<w;j++){
square[i][j] = minCell(square, i, j);
}
}
}
printArray(square);
}
This method will calculate the minimum distance based on the current cell and its 4 neighbors:
static int minCell(int[][] square, int i, int j){
//get the minimum of current cell and adjacent cells + 1.
}
The next two methods are for input/output (see link for full code):
private static void printArray(int[][] square) {
//print the Array
}
public static void main(String[] args) {
//get input into arrays
}
}
Upvotes: 2
Reputation: 11805
I know this may be just solving your homework, but I had to.
Here is an efficient way of solving your problem in JavaScript, I believe it is only O(n^2) (I'm a little rusty on O notation, and ignore the first loop which may be completed on data entry)
It works as follows
Get each elements position
for (var a=0,aa=arr.length; a<aa; a++) // this loop may be able to be done when data is read in
{
result[a] = [];
for (var b=0,bb=arr[a].length; b<bb; b++)
{
result[a][b] = -1;
if(arr[a][b]==1)pos.push({x:a,y:b,dist:0});
}
}
Start looping through array
Grabbing the first entry and removing it. In c++ you should use a queue
while(pos.length>0)
{
var p = pos[0];
pos.splice(0,1);
Check if the distance hasn't already been set
if(result[p.x][p.y]==-1)
{
Check if the x and y coordinates are within the bounds of the array
Add them to the end of the position array/queue, along with an extra distance unit
var x = p.x+dx[a];
var y = p.y+dy[a];
if(x>=0&&x<result.length&&y>=0&&y<result[p.x].length)pos.push({x:x,y:y,dist:p.dist+1});
Display output
for (var a=0,aa=arr.length; a<aa; a++)
{
console.log(result[a]);
}
The full code:
<script>
var arr = [
[0,0,0,0],
[0,0,0,1],
[1,0,0,0],
[1,0,0,0]];
var result = [];
var pos = [];
for (var a=0,aa=arr.length; a<aa; a++) // this loop may be able to be done when data is read in
{
result[a] = [];
for (var b=0,bb=arr[a].length; b<bb; b++)
{
result[a][b] = -1;
if(arr[a][b]==1)pos.push({x:a,y:b,dist:0});
}
}
var dx = [-1,0,0,1];
var dy = [0,1,-1,0];
while(pos.length>0)
{
var p = pos[0];
pos.splice(0,1);
if(result[p.x][p.y]==-1)
{
result[p.x][p.y] = p.dist;
for(var a=0; a<4; a++)
{
var x = p.x+dx[a];
var y = p.y+dy[a];
if(x>=0&&x<result.length&&y>=0&&y<result[p.x].length)pos.push({x:x,y:y,dist:p.dist+1});
}
}
}
for (var a=0,aa=arr.length; a<aa; a++)
{
console.log(result[a]);
}
</script>
Upvotes: 0
Reputation: 1024
You can iterate over the matrix and find the coordinates of all the 1's (x1, y1). Then for each position in the cell (x2, y2), for all (x1, y1) in your list, find the minimum |x2 - x1| + |y2 - y1| (the Manhattan distance since it's a grid).
Upvotes: 4
Reputation: 10162
Start with a matrix with 0 where the 1 are located and a large number (larger then any possible distance) on the other cells. Then iterate over your matrix. In every cell put the minimum between the current value and the minimum of values of adjacent cells plus one. Iterate until you don't need any update.
Upvotes: 0