2016 Update
This commit is contained in:
parent
948b86eafa
commit
dcf5d15da3
7965 changed files with 139854 additions and 31002 deletions
|
|
@ -1,9 +1,10 @@
|
|||
{{Wikipedia|Closest pair of points problem}}
|
||||
The aim of this task is to provide a function to find the closest two points among a set of given points in two dimensions, i.e. to solve the [[wp:Closest pair of points problem|Closest pair of points problem]] in the ''planar'' case.
|
||||
|
||||
The straightforward solution is a O(n<sup>2</sup>) algorithm
|
||||
(which we can call ''brute-force algorithm'');
|
||||
the pseudocode (using indexes) could be simply:
|
||||
|
||||
;Task:
|
||||
Provide a function to find the closest two points among a set of given points in two dimensions, i.e. to solve the [[wp:Closest pair of points problem|Closest pair of points problem]] in the ''planar'' case.
|
||||
|
||||
The straightforward solution is a O(n<sup>2</sup>) algorithm (which we can call ''brute-force algorithm''); the pseudo-code (using indexes) could be simply:
|
||||
|
||||
'''bruteForceClosestPair''' of P(1), P(2), ... P(N)
|
||||
'''if''' N < 2 '''then'''
|
||||
|
|
@ -22,9 +23,7 @@ the pseudocode (using indexes) could be simply:
|
|||
'''return''' minDistance, minPoints
|
||||
'''endif'''
|
||||
|
||||
A better algorithm is based on the recursive divide&conquer approach,
|
||||
as explained also at [[wp:Closest pair of points problem#Planar_case|Wikipedia]],
|
||||
which is O(''n'' log ''n''); a pseudocode could be:
|
||||
A better algorithm is based on the recursive divide&conquer approach, as explained also at [[wp:Closest pair of points problem#Planar_case|Wikipedia's Closest pair of points problem]], which is O(''n'' log ''n''); a pseudo-code could be:
|
||||
|
||||
'''closestPair''' of (xP, yP)
|
||||
where xP is P(1) .. P(N) sorted by x coordinate, and
|
||||
|
|
@ -59,9 +58,10 @@ which is O(''n'' log ''n''); a pseudocode could be:
|
|||
'''endif'''
|
||||
|
||||
|
||||
'''References and further readings'''
|
||||
* [[wp:Closest pair of points problem|Closest pair of points problem]]
|
||||
* [http://www.cs.mcgill.ca/~cs251/ClosestPair/ClosestPairDQ.html Closest Pair (McGill)]
|
||||
* [http://www.cs.ucsb.edu/~suri/cs235/ClosestPair.pdf Closest Pair (UCSB)]
|
||||
* [http://classes.cec.wustl.edu/~cse241/handouts/closestpair.pdf Closest pair (WUStL)]
|
||||
* [http://www.cs.iupui.edu/~xkzou/teaching/CS580/Divide-and-conquer-closestPair.ppt Closest pair (IUPUI)]
|
||||
;References and further readings:
|
||||
* [[wp:Closest pair of points problem|Closest pair of points problem]]
|
||||
* [http://www.cs.mcgill.ca/~cs251/ClosestPair/ClosestPairDQ.html Closest Pair (McGill)]
|
||||
* [http://www.cs.ucsb.edu/~suri/cs235/ClosestPair.pdf Closest Pair (UCSB)]
|
||||
* [http://classes.cec.wustl.edu/~cse241/handouts/closestpair.pdf Closest pair (WUStL)]
|
||||
* [http://www.cs.iupui.edu/~xkzou/teaching/CS580/Divide-and-conquer-closestPair.ppt Closest pair (IUPUI)]
|
||||
<br><br>
|
||||
|
|
|
|||
|
|
@ -1,19 +1,47 @@
|
|||
defmodule Closest_pair do
|
||||
def bruteForce([p0,p1|_] = points) do
|
||||
pnts = List.to_tuple(points)
|
||||
minDist = distance(p0, p1)
|
||||
n = tuple_size(pnts)
|
||||
{minDistance, minPoints} = Enum.reduce(0..n-2, {minDist, [0,1]}, fn i,{mD,mP} ->
|
||||
Enum.reduce(i+1..n-1, {mD,mP}, fn j,{md,mp} ->
|
||||
dist = distance(elem(pnts,i), elem(pnts,j))
|
||||
if dist < md, do: {dist, [i,j]}, else: {md,mp}
|
||||
end)
|
||||
end)
|
||||
{:math.sqrt(minDistance), minPoints}
|
||||
# brute-force algorithm:
|
||||
def bruteForce([p0,p1|_] = points), do: bf_loop(points, {distance(p0, p1), {p0, p1}})
|
||||
|
||||
defp bf_loop([_], acc), do: acc
|
||||
defp bf_loop([h|t], acc), do: bf_loop(t, bf_loop(h, t, acc))
|
||||
|
||||
defp bf_loop(_, [], acc), do: acc
|
||||
defp bf_loop(p0, [p1|t], {minD, minP}) do
|
||||
dist = distance(p0, p1)
|
||||
if dist < minD, do: bf_loop(p0, t, {dist, {p0, p1}}),
|
||||
else: bf_loop(p0, t, {minD, minP})
|
||||
end
|
||||
|
||||
defp distance({p0x,p0y}, {p1x,p1y}) do
|
||||
(p1x - p0x) * (p1x - p0x) + (p1y - p0y) * (p1y - p0y)
|
||||
:math.sqrt( (p1x - p0x) * (p1x - p0x) + (p1y - p0y) * (p1y - p0y) )
|
||||
end
|
||||
|
||||
# recursive divide&conquer approach:
|
||||
def recursive(points) do
|
||||
recursive(Enum.sort(points), Enum.sort_by(points, fn {_x,y} -> y end))
|
||||
end
|
||||
|
||||
def recursive(xP, _yP) when length(xP) <= 3, do: bruteForce(xP)
|
||||
def recursive(xP, yP) do
|
||||
{xL, xR} = Enum.split(xP, div(length(xP), 2))
|
||||
{xm, _} = hd(xR)
|
||||
{yL, yR} = Enum.partition(yP, fn {x,_} -> x < xm end)
|
||||
{dL, pairL} = recursive(xL, yL)
|
||||
{dR, pairR} = recursive(xR, yR)
|
||||
{dmin, pairMin} = if dL<dR, do: {dL, pairL}, else: {dR, pairR}
|
||||
yS = Enum.filter(yP, fn {x,_} -> abs(xm - x) < dmin end)
|
||||
merge(yS, {dmin, pairMin})
|
||||
end
|
||||
|
||||
defp merge([_], acc), do: acc
|
||||
defp merge([h|t], acc), do: merge(t, merge_loop(h, t, acc))
|
||||
|
||||
defp merge_loop(_, [], acc), do: acc
|
||||
defp merge_loop(p0, [p1|_], {dmin,_}=acc) when dmin <= elem(p1,1) - elem(p0,1), do: acc
|
||||
defp merge_loop(p0, [p1|t], {dmin, pair}) do
|
||||
dist = distance(p0, p1)
|
||||
if dist < dmin, do: merge_loop(p0, t, {dist, {p0, p1}}),
|
||||
else: merge_loop(p0, t, {dmin, pair})
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -22,3 +50,10 @@ data = [{0.654682, 0.925557}, {0.409382, 0.619391}, {0.891663, 0.888594}, {0.716
|
|||
{0.293786, 0.691701}, {0.839186, 0.728260}]
|
||||
|
||||
IO.inspect Closest_pair.bruteForce(data)
|
||||
IO.inspect Closest_pair.recursive(data)
|
||||
|
||||
data2 = for _ <- 1..5000, do: {:rand.uniform, :rand.uniform}
|
||||
IO.puts "\nBrute-force:"
|
||||
IO.inspect :timer.tc(fn -> Closest_pair.bruteForce(data2) end)
|
||||
IO.puts "Recursive divide&conquer:"
|
||||
IO.inspect :timer.tc(fn -> Closest_pair.recursive(data2) end)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
type xy struct {
|
||||
|
|
@ -11,18 +12,17 @@ type xy struct {
|
|||
}
|
||||
|
||||
const n = 1000
|
||||
const scale = 1.
|
||||
const scale = 100.
|
||||
|
||||
func d(p1, p2 xy) float64 {
|
||||
dx := p2.x - p1.x
|
||||
dy := p2.y - p1.y
|
||||
return math.Sqrt(dx*dx + dy*dy)
|
||||
return math.Hypot(p2.x-p1.x, p2.y-p1.y)
|
||||
}
|
||||
|
||||
func main() {
|
||||
rand.Seed(time.Now().Unix())
|
||||
points := make([]xy, n)
|
||||
for i := range points {
|
||||
points[i] = xy{rand.Float64(), rand.Float64() * scale}
|
||||
points[i] = xy{rand.Float64() * scale, rand.Float64() * scale}
|
||||
}
|
||||
p1, p2 := closestPair(points)
|
||||
fmt.Println(p1, p2)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
// number of points to search for closest pair
|
||||
|
|
@ -13,7 +14,7 @@ const n = 1e6
|
|||
|
||||
// size of bounding box for points.
|
||||
// x and y will be random with uniform distribution in the range [0,scale).
|
||||
const scale = 1.
|
||||
const scale = 100.
|
||||
|
||||
// point struct
|
||||
type xy struct {
|
||||
|
|
@ -21,17 +22,15 @@ type xy struct {
|
|||
key int64 // an annotation used in the algorithm
|
||||
}
|
||||
|
||||
// Euclidian distance
|
||||
func d(p1, p2 xy) float64 {
|
||||
dx := p2.x - p1.x
|
||||
dy := p2.y - p1.y
|
||||
return math.Sqrt(dx*dx + dy*dy)
|
||||
return math.Hypot(p2.x-p1.x, p2.y-p1.y)
|
||||
}
|
||||
|
||||
func main() {
|
||||
rand.Seed(time.Now().Unix())
|
||||
points := make([]xy, n)
|
||||
for i := range points {
|
||||
points[i] = xy{rand.Float64(), rand.Float64() * scale, 0}
|
||||
points[i] = xy{rand.Float64() * scale, rand.Float64() * scale, 0}
|
||||
}
|
||||
p1, p2 := closestPair(points)
|
||||
fmt.Println(p1, p2)
|
||||
|
|
@ -64,14 +63,14 @@ func closestPair(s []xy) (p1, p2 xy) {
|
|||
mx := int64(scale*invB) + 1 // mx is number of cells along a side
|
||||
// construct map as a histogram:
|
||||
// key is index into mesh. value is count of points in cell
|
||||
hm := make(map[int64]int)
|
||||
hm := map[int64]int{}
|
||||
for ip, p := range s1 {
|
||||
key := int64(p.x*invB)*mx + int64(p.y*invB)
|
||||
s1[ip].key = key
|
||||
hm[key]++
|
||||
}
|
||||
// construct s2 = s1 less the points without neighbors
|
||||
var s2 []xy
|
||||
s2 := make([]xy, 0, len(s1))
|
||||
nx := []int64{-mx - 1, -mx, -mx + 1, -1, 0, 1, mx - 1, mx, mx + 1}
|
||||
for i, p := range s1 {
|
||||
nn := 0
|
||||
|
|
@ -93,7 +92,7 @@ func closestPair(s []xy) (p1, p2 xy) {
|
|||
// step 4: compute answer from approximation
|
||||
invB := 1 / dxi
|
||||
mx := int64(scale*invB) + 1
|
||||
hm := make(map[int64][]int)
|
||||
hm := map[int64][]int{}
|
||||
for i, p := range s {
|
||||
key := int64(p.x*invB)*mx + int64(p.y*invB)
|
||||
s[i].key = key
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
vecl =: +/"1&.:*: NB. length of each of vectors
|
||||
vecl =: +/"1&.:*: NB. length of each vector
|
||||
dist =: <@:vecl@:({: -"1 }:)\ NB. calculate all distances among vectors
|
||||
minpair=: ({~ > {.@($ #: I.@,)@:= <./@;)dist NB. find one pair of the closest points
|
||||
closestpairbf =: (; vecl@:-/)@minpair NB. the pair and their distance
|
||||
|
|
|
|||
67
Task/Closest-pair-problem/Pascal/closest-pair-problem.pascal
Normal file
67
Task/Closest-pair-problem/Pascal/closest-pair-problem.pascal
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
program closestPoints;
|
||||
{$IFDEF FPC}
|
||||
{$MODE Delphi}
|
||||
{$ENDIF}
|
||||
const
|
||||
PointCnt = 10000;//31623;
|
||||
type
|
||||
TdblPoint = Record
|
||||
ptX,
|
||||
ptY : double;
|
||||
end;
|
||||
tPtLst = array of TdblPoint;
|
||||
|
||||
tMinDIstIdx = record
|
||||
md1,
|
||||
md2 : NativeInt;
|
||||
end;
|
||||
|
||||
function ClosPointBruteForce(var ptl :tPtLst):tMinDIstIdx;
|
||||
Var
|
||||
i,j,k : NativeInt;
|
||||
mindst2,dst2: double; //square of distance, no need to sqrt
|
||||
p0,p1 : ^TdblPoint; //using pointer, since calc of ptl[?] takes much time
|
||||
Begin
|
||||
i := Low(ptl);
|
||||
j := High(ptl);
|
||||
result.md1 := i;result.md2 := j;
|
||||
mindst2 := sqr(ptl[i].ptX-ptl[j].ptX)+sqr(ptl[i].ptY-ptl[j].ptY);
|
||||
repeat
|
||||
p0 := @ptl[i];
|
||||
p1 := p0; inc(p1);
|
||||
For k := i+1 to j do
|
||||
Begin
|
||||
dst2:= sqr(p0^.ptX-p1^.ptX)+sqr(p0^.ptY-p1^.ptY);
|
||||
IF mindst2 > dst2 then
|
||||
Begin
|
||||
mindst2 := dst2;
|
||||
result.md1 := i;
|
||||
result.md2 := k;
|
||||
end;
|
||||
inc(p1);
|
||||
end;
|
||||
inc(i);
|
||||
until i = j;
|
||||
end;
|
||||
|
||||
var
|
||||
PointLst :tPtLst;
|
||||
cloPt : tMinDIstIdx;
|
||||
i : NativeInt;
|
||||
Begin
|
||||
randomize;
|
||||
setlength(PointLst,PointCnt);
|
||||
For i := 0 to PointCnt-1 do
|
||||
with PointLst[i] do
|
||||
Begin
|
||||
ptX := random;
|
||||
ptY := random;
|
||||
end;
|
||||
cloPt:= ClosPointBruteForce(PointLst) ;
|
||||
i := cloPt.md1;
|
||||
Writeln('P[',i:4,']= x: ',PointLst[i].ptX:0:8,
|
||||
' y: ',PointLst[i].ptY:0:8);
|
||||
i := cloPt.md2;
|
||||
Writeln('P[',i:4,']= x: ',PointLst[i].ptX:0:8,
|
||||
' y: ',PointLst[i].ptY:0:8);
|
||||
end.
|
||||
|
|
@ -1,33 +1,32 @@
|
|||
/*REXX program solves the closest pair of points problem in two dimensions.*/
|
||||
parse arg N low high seed . /*obtain optional arguments from the CL*/
|
||||
if N=='' | N==',' then N=100 /*Not specified? Then use the default.*/
|
||||
if low=='' | low==',' then low=0 /* " " " " " " */
|
||||
if high=='' |high==',' then high=20000 /* " " " " " " */
|
||||
if datatype(seed,'W') then call random ,,seed /*seed for RANDOM repeatable.*/
|
||||
/*REXX program solves the closest pair of points problem (in two dimensions). */
|
||||
parse arg N low high seed . /*obtain optional arguments from the CL*/
|
||||
if N=='' | N=="," then N= 100 /*Not specified? Then use the default.*/
|
||||
if low=='' | low=="," then low= 0 /* " " " " " " */
|
||||
if high=='' | high=="," then high=20000 /* " " " " " " */
|
||||
if datatype(seed,'W') then call random ,,seed /*seed for RANDOM (BIF) repeatability.*/
|
||||
w=length(high); w=w + (w//2==0)
|
||||
/*╔══════════════════════╗*/ do j=1 for N /*generate N random points. */
|
||||
/*║ generate N points. ║*/ @x.j=random(low,high) /*a random X. */
|
||||
/*╚══════════════════════╝*/ @y.j=random(low,high) /*" " Y. */
|
||||
end /*j*/
|
||||
A=1; B=2
|
||||
minDD=(@x.A-@x.B)**2 + (@y.A-@y.B)**2 /*distance between first two points. */
|
||||
/*╔══════════════════════╗*/ do j=1 for N /*generate N random points.*/
|
||||
/*║ generate N points. ║*/ @x.j=random(low,high) /* " a random X. */
|
||||
/*╚══════════════════════╝*/ @y.j=random(low,high) /* " " " Y. */
|
||||
end /*j*/ /*X and Y make the point*/
|
||||
A=1; B=2 /* [↓] MINDD is actually the unsquared*/
|
||||
minDD=(@x.A-@x.B)**2 + (@y.A-@y.B)**2 /*distance between the first two points*/
|
||||
/* [↓] use of XJ & YJ speed things up.*/
|
||||
do j=1 for N-1; xj=@x.j; yj=@y.j /*find minimum distance between a ··· */
|
||||
do k=j+1 to N /* ··· point and all the other points.*/
|
||||
dd=(xj - @x.k)**2 + (yj - @y.k)**2 /*compute squared distance from points.*/
|
||||
if dd<minDD then if dd\=0 then parse value dd j k with minDD A B
|
||||
end /*k*/ /* [↑] needn't take SQRT of DD (yet).*/
|
||||
end /*j*/ /* [↑] when done, A & B are the ones*/
|
||||
|
||||
do j=1 for N-1 /*find minimum distance between a ··· */
|
||||
do k=j+1 to N /* ··· point and all the other points.*/
|
||||
dd=(@x.j - @x.k)**2 + (@y.j - @y.k)**2
|
||||
if dd\=0 then if dd<minDD then do; minDD=dd; A=j; B=k; end
|
||||
end /*k*/
|
||||
end /*j*/ /* [↑] when done, A & B are the ones*/
|
||||
|
||||
_= 'For ' N " points, the minimum distance between the two points: "
|
||||
say _ center("x",w,'═')" " center('y',w,"═") ' is: ' sqrt(abs(minDD))
|
||||
say left('', length(_)-1) '['right(@x.A, w)"," right(@y.A, w)"]"
|
||||
say left('', length(_)-1) '['right(@x.B, w)"," right(@y.B, w)"]"
|
||||
exit /*stick a fork in it, we're all done. */
|
||||
/*────────────────────────────────────────────────────────────────────────────*/
|
||||
sqrt: procedure; parse arg x; if x=0 then return 0; d=digits(); i=; m.=9
|
||||
numeric digits 9; numeric form; h=d+6; if x<0 then do; x=-x; i='i'; end
|
||||
parse value format(x,2,1,,0) 'E0' with g 'E' _ .; g=g*.5'e'_%2
|
||||
do j=0 while h>9; m.j=h; h=h%2+1; end /*j*/
|
||||
do k=j+5 to 0 by -1; numeric digits m.k; g=(g+x/g)*.5; end /*k*/
|
||||
numeric digits d; return (g/1)i /*make complex if X < 0.*/
|
||||
_= 'For ' N " points, the minimum distance between the two points: "
|
||||
say _ center("x", w, '═')" " center('y', w, "═") ' is: ' sqrt(abs(minDD))/1
|
||||
say left('', length(_)-1) "["right(@x.A, w)',' right(@y.A, w)"]"
|
||||
say left('', length(_)-1) "["right(@x.B, w)',' right(@y.B, w)"]"
|
||||
exit /*stick a fork in it, we're all done. */
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
sqrt: procedure; parse arg x; if x=0 then return 0; d=digits(); m.=9; numeric form; h=d+6
|
||||
numeric digits; parse value format(x,2,1,,0) 'E0' with g 'E' _ .; g=g *.5'e'_ % 2
|
||||
do j=0 while h>9; m.j=h; h=h%2+1; end /*j*/
|
||||
do k=j+5 to 0 by -1; numeric digits m.k; g=(g+x/g)*.5; end /*k*/
|
||||
return g
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
10 DIM x(10): DIM y(10)
|
||||
20 FOR i=1 TO 10
|
||||
30 READ x(i),y(i)
|
||||
40 NEXT i
|
||||
50 LET min=1e30
|
||||
60 FOR i=1 TO 9
|
||||
70 FOR j=i+1 TO 10
|
||||
80 LET p1=x(i)-x(j): LET p2=y(i)-y(j): LET dsq=p1*p1+p2*p2
|
||||
90 IF dsq<min THEN LET min=dsq: LET mini=i: LET minj=j
|
||||
100 NEXT j
|
||||
110 NEXT i
|
||||
120 PRINT "Closest pair is ";mini;" and ";minj;" at distance ";SQR min
|
||||
130 STOP
|
||||
140 DATA 0.654682,0.925557
|
||||
150 DATA 0.409382,0.619391
|
||||
160 DATA 0.891663,0.888594
|
||||
170 DATA 0.716629,0.996200
|
||||
180 DATA 0.477721,0.946355
|
||||
190 DATA 0.925092,0.818220
|
||||
200 DATA 0.624291,0.142924
|
||||
210 DATA 0.211332,0.221507
|
||||
220 DATA 0.293786,0.691701
|
||||
230 DATA 0.839186,0.728260
|
||||
Loading…
Add table
Add a link
Reference in a new issue