# Tricky Median Question

Given n points, choose a point in the given list such that the sum of distances to this point is minimum ,compared to all others.

Distance is measured in the following manner.

For a point (x,y) all 8 adjacent points have distance 1.

(x+1,y)(x+1,y+1),(x+1,y-1),(x,y+1),(x,y-1),(x-1,y)(x-1,y+1),(x-1,y-1)


EDIT

More clearer explanation.

A function foo is defined as

foo(point_a,point_b) = max(abs(point_a.x - point_b.x),abs(point_a.y - point_b.y))


Find a point x such that sum([foo(x,y) for y in list_of_points]) is minimum.

Example

Input:

0 1
2 5
3 1
4 0


Output

3 1


Eg: Distance between (4,5) and 6,7) is 2.

This can be done in O(n^2) time, by checking the sum of each pair. Is there any better algorithm to do it?

• I don't understand how the diagonal distances are the same as the perpendicular distances. Also, I'm not sure I understand: are you you asking for the average of the n points? – Griffin Aug 14 '11 at 20:12
• Edited the question – Greyhound Aug 14 '11 at 20:20
• This isn't really a puzzle - wouldn't it belong to SO? – user unknown Aug 15 '11 at 4:03
• Crossposting: stackoverflow.com/q/7059500/312172 (with python-tag, there) – user unknown Aug 15 '11 at 4:06
• @user unknown: How do you define "puzzle"? For me, the puzzle is finding the more efficient algorithm, and I'm having fun working it out. – Joey Adams Aug 15 '11 at 10:11

I can imagine a scheme better than O(n^2), at least in the common case.

Build a quadtree out of your input points. For each node in the tree, compute the number and average position of the points within that node. Then for each point, you can use the quadtree to compute its distance to all other points in less than O(n) time. If you're computing the distance from a point p to a distant quadtree node v, and v doesn't overlap the 45 degree diagonals from p, then the total distance from p to all the points in v is easy to compute (for v which are more horizontally than vertically separated from p, it is just v.num_points * |p.x - v.average.x|, and similarly using y coordinates if v is predominately vertically seperated). If v overlaps one of the 45 degree diagonals, recurse on its components.

That should beat O(n^2), at least when you can find a balanced quadtree to represent your points.

• nice. this should be on the stackoverflow page. – Neil G Aug 17 '11 at 20:41

## Python

def median(lst):
""" sort of median of a list """
return sorted(lst)[len(lst) / 2]

def median_point(points):
xs = [point for point in points]
ys = [point for point in points]
return (median(xs), median(ys))

points = [
(0, 1),
(2, 5),
(3, 1),
(4, 0),
]

print median_point(points) # (3, 1)


It calculates the median of the x and y coordinates separately. I'm not positive that that's correct in all cases, but it kind of seems like it might be. It's O(n log n).

• Calculating the medians separately means you may get a result that isn't one of the original points. In your example, if you replace (3,1) and (4,0) with (3,0) and (4,1), it will still print out (3,1). – migimaru Aug 17 '11 at 23:38
• Ah yes, I didn't notice that was a requirement. – recursive Aug 18 '11 at 1:45

## Scala

object Median extends App
{
var(xMin,yMin,xMax,yMax,a,x)=(100000000,100000000,-100000000,-100000000,"",Array.fill(2)(""))
var points=Array((100000000,100000000))
while(a!=null)
{
x=a.split(" ")
if(x(0).toInt<xMin)xMin=x(0).toInt
if(x(1).toInt<yMin)yMin=x(1).toInt
if(x(0).toInt>xMax)xMax=x(0).toInt
if(x(1).toInt>yMax)yMax=x(1).toInt
points=points:+((x(0).toInt,x(1).toInt))
}
var middlex=(xMax-xMin)/2
var middley=(yMax-yMin)/2

var meanPoint=(100000000,100000000)
var shortestDistance=100000000

points.map(x=>
{
var s=(math.abs(x._1-middlex).max(math.abs(x._2-middley)))
if(s<shortestDistance)
{
shortestDistance=s
meanPoint=x
}
})

println(meanPoint)
}


Takes in the points, keeping track of the highest and lowest values of x and y.
Uses those values to find the midpoint of the square defined by xMin,yMin,xMax,yMax.
Finds the point with the shortest distance to that midpoint.

Never was very good with that Big O business, so I couldn't tell you what it is for this algorithm.

• I don't think that will give you the correct answer, especially if the points are clustered. For example, if the points are (0,0) (0,1) (0,2) (1,0) (1,1) (1,2) (2,0) (2,1) (2,2) (10,10), the correct answer should be (1,1) - total distance of 17. Yours would return (2,2) - total distance of 21. – migimaru Aug 15 '11 at 0:03
• @migimaru Hmmm...I'll have to rethink. – Gareth Aug 15 '11 at 7:05

main=interact$show.n.q.map read.words n x=snd$minimum$map(\p@(a,b)->(sum$map(\(x,y)->max(abs$a-x)$abs\$b-y)x,p))x