Just another update
This commit is contained in:
parent
a25938f123
commit
00a190b0a6
6591 changed files with 94363 additions and 23227 deletions
|
|
@ -1,7 +1,9 @@
|
|||
{{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:
|
||||
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:
|
||||
|
||||
'''bruteForceClosestPair''' of P(1), P(2), ... P(N)
|
||||
'''if''' N < 2 '''then'''
|
||||
|
|
@ -20,7 +22,9 @@ The straightforward solution is a O(n<sup>2</sup>) algorithm (which we can call
|
|||
'''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]],
|
||||
which is O(''n'' log ''n''); a pseudocode could be:
|
||||
|
||||
'''closestPair''' of (xP, yP)
|
||||
where xP is P(1) .. P(N) sorted by x coordinate, and
|
||||
|
|
|
|||
115
Task/Closest-pair-problem/C++/closest-pair-problem.cpp
Normal file
115
Task/Closest-pair-problem/C++/closest-pair-problem.cpp
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
Author: Kevin Bacon
|
||||
Date: 04/03/2014
|
||||
Task: Closest-pair problem
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <cmath>
|
||||
#include <random>
|
||||
#include <chrono>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
typedef std::pair<double, double> point_t;
|
||||
typedef std::pair<point_t, point_t> points_t;
|
||||
|
||||
double distance_between(const point_t& a, const point_t& b) {
|
||||
return std::sqrt(std::pow(b.first - a.first, 2)
|
||||
+ std::pow(b.second - a.second, 2));
|
||||
}
|
||||
|
||||
std::pair<double, points_t> find_closest_brute(const std::vector<point_t>& points) {
|
||||
if (points.size() < 2) {
|
||||
return { -1, { { 0, 0 }, { 0, 0 } } };
|
||||
}
|
||||
auto minDistance = std::abs(distance_between(points.at(0), points.at(1)));
|
||||
points_t minPoints = { points.at(0), points.at(1) };
|
||||
for (auto i = std::begin(points); i != (std::end(points) - 1); ++i) {
|
||||
for (auto j = i + 1; j < std::end(points); ++j) {
|
||||
auto newDistance = std::abs(distance_between(*i, *j));
|
||||
if (newDistance < minDistance) {
|
||||
minDistance = newDistance;
|
||||
minPoints.first = *i;
|
||||
minPoints.second = *j;
|
||||
}
|
||||
}
|
||||
}
|
||||
return { minDistance, minPoints };
|
||||
}
|
||||
|
||||
std::pair<double, points_t> find_closest_optimized(const std::vector<point_t>& xP,
|
||||
const std::vector<point_t>& yP) {
|
||||
if (xP.size() <= 3) {
|
||||
return find_closest_brute(xP);
|
||||
}
|
||||
auto N = xP.size();
|
||||
auto xL = std::vector<point_t>();
|
||||
auto xR = std::vector<point_t>();
|
||||
std::copy(std::begin(xP), std::begin(xP) + (N / 2), std::back_inserter(xL));
|
||||
std::copy(std::begin(xP) + (N / 2), std::end(xP), std::back_inserter(xR));
|
||||
auto xM = xP.at(N / 2).first;
|
||||
auto yL = std::vector<point_t>();
|
||||
auto yR = std::vector<point_t>();
|
||||
std::copy_if(std::begin(yP), std::end(yP), std::back_inserter(yL), [&xM](const point_t& p) {
|
||||
return p.first <= xM;
|
||||
});
|
||||
std::copy_if(std::begin(yP), std::end(yP), std::back_inserter(yR), [&xM](const point_t& p) {
|
||||
return p.first > xM;
|
||||
});
|
||||
auto p1 = find_closest_optimized(xL, yL);
|
||||
auto p2 = find_closest_optimized(xR, yR);
|
||||
auto minPair = (p1.first <= p2.first) ? p1 : p2;
|
||||
auto yS = std::vector<point_t>();
|
||||
std::copy_if(std::begin(yP), std::end(yP), std::back_inserter(yS), [&minPair, &xM](const point_t& p) {
|
||||
return std::abs(xM - p.first) < minPair.first;
|
||||
});
|
||||
auto result = minPair;
|
||||
for (auto i = std::begin(yS); i != (std::end(yS) - 1); ++i) {
|
||||
for (auto k = i + 1; k != std::end(yS) &&
|
||||
((k->second - i->second) < minPair.first); ++k) {
|
||||
auto newDistance = std::abs(distance_between(*k, *i));
|
||||
if (newDistance < result.first) {
|
||||
result = { newDistance, { *k, *i } };
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void print_point(const point_t& point) {
|
||||
std::cout << "(" << point.first
|
||||
<< ", " << point.second
|
||||
<< ")";
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
std::default_random_engine re(std::chrono::system_clock::to_time_t(
|
||||
std::chrono::system_clock::now()));
|
||||
std::uniform_real_distribution<double> urd(-500.0, 500.0);
|
||||
std::vector<point_t> points(100);
|
||||
std::generate(std::begin(points), std::end(points), [&urd, &re]() {
|
||||
return point_t { 1000 + urd(re), 1000 + urd(re) };
|
||||
});
|
||||
auto answer = find_closest_brute(points);
|
||||
std::sort(std::begin(points), std::end(points), [](const point_t& a, const point_t& b) {
|
||||
return a.first < b.first;
|
||||
});
|
||||
auto xP = points;
|
||||
std::sort(std::begin(points), std::end(points), [](const point_t& a, const point_t& b) {
|
||||
return a.second < b.second;
|
||||
});
|
||||
auto yP = points;
|
||||
std::cout << "Min distance (brute): " << answer.first << " ";
|
||||
print_point(answer.second.first);
|
||||
std::cout << ", ";
|
||||
print_point(answer.second.second);
|
||||
answer = find_closest_optimized(xP, yP);
|
||||
std::cout << "\nMin distance (optimized): " << answer.first << " ";
|
||||
print_point(answer.second.first);
|
||||
std::cout << ", ";
|
||||
print_point(answer.second.second);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,12 +1,9 @@
|
|||
import std.stdio, std.typecons, std.math, std.algorithm,
|
||||
std.random, std.traits, std.range, std.complex;
|
||||
|
||||
//auto bfClosestPair(T)(in T[] points) pure nothrow {
|
||||
auto bruteForceClosestPair(T)(in T[] points) pure nothrow @nogc {
|
||||
// return pairwise(points.length.iota, points.length.iota)
|
||||
// .reduce!(min!((i, j) => abs(points[i] - points[j])));
|
||||
//}
|
||||
|
||||
auto bruteForceClosestPair(T)(in T[] points) pure nothrow {
|
||||
auto minD = Unqual!(typeof(T.re)).infinity;
|
||||
T minI, minJ;
|
||||
foreach (immutable i, const p1; points.dropBackOne)
|
||||
|
|
@ -21,7 +18,7 @@ auto bruteForceClosestPair(T)(in T[] points) pure nothrow {
|
|||
return tuple(minD, minI, minJ);
|
||||
}
|
||||
|
||||
auto closestPair(T)(T[] points) /*pure nothrow*/ {
|
||||
auto closestPair(T)(T[] points) pure nothrow {
|
||||
static Tuple!(typeof(T.re), T, T) inner(in T[] xP, /*in*/ T[] yP)
|
||||
pure nothrow {
|
||||
if (xP.length <= 3)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import std.stdio, std.random, std.math, std.typecons, std.complex,
|
|||
std.traits;
|
||||
|
||||
Nullable!(Tuple!(size_t, size_t))
|
||||
bfClosestPair2(T)(in Complex!T[] points) pure nothrow {
|
||||
bfClosestPair2(T)(in Complex!T[] points) pure nothrow @nogc {
|
||||
auto minD = Unqual!(typeof(points[0].re)).infinity;
|
||||
if (points.length < 2)
|
||||
return typeof(return)();
|
||||
|
|
|
|||
|
|
@ -1,37 +1,32 @@
|
|||
/*REXX program to solve the closest pair problem. */
|
||||
parse arg N low high seed .; if n=='' then n=100
|
||||
if seed\=='' then call random ,,seed /*use seed, makes rand repeatable*/
|
||||
if low=='' | low==',' then low=0
|
||||
if high=='' | high==',' then high=20000
|
||||
w=length(high); w=w + (w//2==0)
|
||||
do j=1 for N /*gen random points*/
|
||||
@.j.xx=random(low,high)
|
||||
@.j.yy=random(low,high)
|
||||
/*REXX program solves the closest pair of points problem in 2 dimensions*/
|
||||
parse arg N low high seed . /*get optional arguments from CL.*/
|
||||
if N=='' | N==',' then N=100 /*N not specified? Use default.*/
|
||||
if low=='' | low==',' then low=0
|
||||
if high=='' | high==',' then high=20000
|
||||
if seed\==''& seed\==',' then call random ,,seed /*seed for repeatable.*/
|
||||
w=length(high); w=w + (w//2==0)
|
||||
/*╔══════════════════════╗*/ do j=1 for N /*gen N random pts.*/
|
||||
/*║ generate N points. ║*/ @x.j=random(low,high) /*random X.*/
|
||||
/*╚══════════════════════╝*/ @y.j=random(low,high) /* " Y.*/
|
||||
end /*j*/
|
||||
nearA=1
|
||||
nearB=2
|
||||
minDD=(@.nearA.xx-@.nearB.xx)**2 + (@.nearA.yy-@.nearB.yy)**2
|
||||
A=1; B=2
|
||||
minDD=(@x.A-@x.B)**2 + (@y.A-@y.B)**2 /*distance between 1st two points*/
|
||||
|
||||
do j=1 for N-1
|
||||
do k=j+1 to N
|
||||
dd=(@.j.xx-@.k.xx)**2 + (@.j.yy-@.k.yy)**2
|
||||
if dd\=0 then if dd<minDD then do; minDD=dd
|
||||
nearA=j
|
||||
nearB=k
|
||||
end
|
||||
end /*k*/
|
||||
end /*j*/
|
||||
do j=1 for N-1 /*find min 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 it*/
|
||||
|
||||
say 'For' N "points:"; say
|
||||
say ' 'center('x',w,"═")' ' center('y',w,"═")
|
||||
say 'The points ['right(@.nearA.xx,w)"," right(@.nearA.yy,w)"]" ' and'
|
||||
say ' ['right(@.nearB.xx,w)"," right(@.nearB.yy,w)"]"; say
|
||||
say 'the minimum distance between them is: ' sqrt(abs(minDD))
|
||||
_= '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 done.*/
|
||||
/*───────────────────────────────────sqrt subroutine────────────────────*/
|
||||
sqrt: procedure; parse arg x; if x=0 then return 0;d=digits();numeric digits 11
|
||||
g=.sqrtG(); do j=0 while p>9; m.j=p; p=p%2+1; end
|
||||
do k=j+5 to 0 by -1; if m.k>11 then numeric digits m.k; g=.5*(g+x/g); end
|
||||
numeric digits d; return g/1
|
||||
.sqrtG: numeric form; m.=11; p=d+d%4+2
|
||||
parse value format(x,2,1,,0) 'E0' with g 'E' _ .; return g*.5'E'_%2
|
||||
/*──────────────────────────────────SQRT subroutine───────────────────────*/
|
||||
sqrt: procedure; parse arg x; if x=0 then return 0; d=digits(); numeric form
|
||||
numeric digits 11;p=d+d%4+2;parse value format(x,2,1,,0) 'E0' with g 'E' _ .
|
||||
g=g*.5'E'_%2; m.=11; do j=0 while p>9; m.j=p; p=p%2+1; end
|
||||
do k=j+5 to 0 by -1; if m.k>11 then numeric digits m.k; g=.5*(g+x/g); end
|
||||
numeric digits d; return g/1
|
||||
|
|
|
|||
|
|
@ -6,36 +6,26 @@ end
|
|||
|
||||
def closest_bruteforce(points)
|
||||
mindist, minpts = Float::MAX, []
|
||||
points.length.times do |i|
|
||||
(i+1).upto(points.length - 1) do |j|
|
||||
dist = distance(points[i], points[j])
|
||||
if dist < mindist
|
||||
mindist = dist
|
||||
minpts = [points[i], points[j]]
|
||||
end
|
||||
points.combination(2) do |pi,pj|
|
||||
dist = distance(pi, pj)
|
||||
if dist < mindist
|
||||
mindist = dist
|
||||
minpts = [pi, pj]
|
||||
end
|
||||
end
|
||||
[mindist, minpts]
|
||||
end
|
||||
|
||||
def closest_recursive(points)
|
||||
if points.length <= 3
|
||||
return closest_bruteforce(points)
|
||||
end
|
||||
xP = points.sort_by {|p| p.x}
|
||||
mid = (points.length / 2.0).ceil
|
||||
pL = xP[0,mid]
|
||||
pR = xP[mid..-1]
|
||||
dL, pairL = closest_recursive(pL)
|
||||
dR, pairR = closest_recursive(pR)
|
||||
if dL < dR
|
||||
dmin, dpair = dL, pairL
|
||||
else
|
||||
dmin, dpair = dR, pairR
|
||||
end
|
||||
yP = xP.find_all {|p| (pL[-1].x - p.x).abs < dmin}.sort_by {|p| p.y}
|
||||
closest = Float::MAX
|
||||
closestPair = []
|
||||
return closest_bruteforce(points) if points.length <= 3
|
||||
xP = points.sort_by(&:x)
|
||||
mid = points.length / 2
|
||||
xm = xP[mid].x
|
||||
dL, pairL = closest_recursive(xP[0,mid])
|
||||
dR, pairR = closest_recursive(xP[mid..-1])
|
||||
dmin, dpair = dL<dR ? [dL, pairL] : [dR, pairR]
|
||||
yP = xP.find_all {|p| (xm - p.x).abs < dmin}.sort_by(&:y)
|
||||
closest, closestPair = dmin, dpair
|
||||
0.upto(yP.length - 2) do |i|
|
||||
(i+1).upto(yP.length - 1) do |k|
|
||||
break if (yP[k].y - yP[i].y) >= dmin
|
||||
|
|
@ -46,14 +36,9 @@ def closest_recursive(points)
|
|||
end
|
||||
end
|
||||
end
|
||||
if closest < dmin
|
||||
[closest, closestPair]
|
||||
else
|
||||
[dmin, dpair]
|
||||
end
|
||||
[closest, closestPair]
|
||||
end
|
||||
|
||||
|
||||
points = Array.new(100) {Point.new(rand, rand)}
|
||||
p ans1 = closest_bruteforce(points)
|
||||
p ans2 = closest_recursive(points)
|
||||
|
|
|
|||
|
|
@ -1,24 +1,133 @@
|
|||
import scala.util._
|
||||
import scala.collection.mutable.ListBuffer
|
||||
import scala.util.Random
|
||||
|
||||
object ClosestPair{
|
||||
class Point(x:Double, y:Double) extends Pair(x,y){
|
||||
def distance(p:Point)=math.hypot(_1-p._1, _2-p._2)
|
||||
}
|
||||
object ClosestPair {
|
||||
case class Point(x: Double, y: Double){
|
||||
def distance(p: Point) = math.hypot(x-p.x, y-p.y)
|
||||
|
||||
def closestPairBF(a:Array[Point])={
|
||||
var minDist=a(0) distance a(1)
|
||||
var minPoints=(a(0), a(1))
|
||||
override def toString = "(" + x + ", " + y + ")"
|
||||
}
|
||||
|
||||
for(p1<-a; p2<-a if p1.ne(p2); dist=p1 distance p2 if(dist<minDist)){
|
||||
minDist=dist;
|
||||
minPoints=(p1, p2)
|
||||
case class Pair(point1: Point, point2: Point) {
|
||||
val distance: Double = point1 distance point2
|
||||
|
||||
override def toString = {
|
||||
point1 + "-" + point2 + " : " + distance
|
||||
}
|
||||
}
|
||||
|
||||
def sortByX(points: List[Point]) = {
|
||||
points.sortBy(point => point.x)
|
||||
}
|
||||
|
||||
def sortByY(points: List[Point]) = {
|
||||
points.sortBy(point => point.y)
|
||||
}
|
||||
|
||||
def divideAndConquer(points: List[Point]): Pair = {
|
||||
val pointsSortedByX = sortByX(points)
|
||||
val pointsSortedByY = sortByY(points)
|
||||
|
||||
divideAndConquer(pointsSortedByX, pointsSortedByY)
|
||||
}
|
||||
|
||||
def bruteForce(points: List[Point]): Pair = {
|
||||
val numPoints = points.size
|
||||
if (numPoints < 2)
|
||||
return null
|
||||
var pair = Pair(points(0), points(1))
|
||||
if (numPoints > 2) {
|
||||
for (i <- 0 until numPoints - 1) {
|
||||
val point1 = points(i)
|
||||
for (j <- i + 1 until numPoints) {
|
||||
val point2 = points(j)
|
||||
val distance = point1 distance point2
|
||||
if (distance < pair.distance)
|
||||
pair = Pair(point1, point2)
|
||||
}
|
||||
}
|
||||
(minPoints, minDist)
|
||||
}
|
||||
}
|
||||
return pair
|
||||
}
|
||||
|
||||
def main(args: Array[String]): Unit = {
|
||||
val a=Array.fill(1000)(new Point(Random.nextDouble, Random.nextDouble))
|
||||
val (points, dist)=closestPairBF(a)
|
||||
println("min: "+points._1+" - "+points._2+" ->"+dist)
|
||||
}
|
||||
|
||||
private def divideAndConquer(pointsSortedByX: List[Point], pointsSortedByY: List[Point]): Pair = {
|
||||
val numPoints = pointsSortedByX.size
|
||||
if(numPoints <= 3) {
|
||||
return bruteForce(pointsSortedByX)
|
||||
}
|
||||
|
||||
val dividingIndex = numPoints >>> 1
|
||||
val leftOfCenter = pointsSortedByX.slice(0, dividingIndex)
|
||||
val rightOfCenter = pointsSortedByX.slice(dividingIndex, numPoints)
|
||||
|
||||
var tempList = leftOfCenter.map(x => x)
|
||||
//println(tempList)
|
||||
tempList = sortByY(tempList)
|
||||
var closestPair = divideAndConquer(leftOfCenter, tempList)
|
||||
|
||||
tempList = rightOfCenter.map(x => x)
|
||||
tempList = sortByY(tempList)
|
||||
|
||||
val closestPairRight = divideAndConquer(rightOfCenter, tempList)
|
||||
|
||||
if (closestPairRight.distance < closestPair.distance)
|
||||
closestPair = closestPairRight
|
||||
|
||||
tempList = List[Point]()
|
||||
val shortestDistance = closestPair.distance
|
||||
val centerX = rightOfCenter(0).x
|
||||
|
||||
for (point <- pointsSortedByY) {
|
||||
if (Math.abs(centerX - point.x) < shortestDistance)
|
||||
tempList = tempList :+ point
|
||||
}
|
||||
|
||||
closestPair = shortestDistanceF(tempList, shortestDistance, closestPair)
|
||||
closestPair
|
||||
}
|
||||
|
||||
private def shortestDistanceF(tempList: List[Point], shortestDistance: Double, closestPair: Pair ): Pair = {
|
||||
var shortest = shortestDistance
|
||||
var bestResult = closestPair
|
||||
for (i <- 0 until tempList.size) {
|
||||
val point1 = tempList(i)
|
||||
for (j <- i + 1 until tempList.size) {
|
||||
val point2 = tempList(j)
|
||||
if ((point2.y - point1.y) >= shortestDistance)
|
||||
return closestPair
|
||||
val distance = point1 distance point2
|
||||
if (distance < closestPair.distance)
|
||||
{
|
||||
bestResult = Pair(point1, point2)
|
||||
shortest = distance
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closestPair
|
||||
}
|
||||
|
||||
def main(args: Array[String]) {
|
||||
val numPoints = if(args.length == 0) 1000 else args(0).toInt
|
||||
|
||||
val points = ListBuffer[Point]()
|
||||
val r = new Random()
|
||||
for (i <- 0 until numPoints) {
|
||||
points.+=:(new Point(r.nextDouble(), r.nextDouble()))
|
||||
}
|
||||
println("Generated " + numPoints + " random points")
|
||||
|
||||
var startTime = System.currentTimeMillis()
|
||||
val bruteForceClosestPair = bruteForce(points.toList)
|
||||
var elapsedTime = System.currentTimeMillis() - startTime
|
||||
println("Brute force (" + elapsedTime + " ms): " + bruteForceClosestPair)
|
||||
|
||||
startTime = System.currentTimeMillis()
|
||||
val dqClosestPair = divideAndConquer(points.toList)
|
||||
elapsedTime = System.currentTimeMillis() - startTime
|
||||
println("Divide and conquer (" + elapsedTime + " ms): " + dqClosestPair)
|
||||
if (bruteForceClosestPair.distance != dqClosestPair.distance)
|
||||
println("MISMATCH")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue