Task: Closest-pair problem


C++: 

#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-1) / 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;
}







VB: Option Explicit

Private Type MyPoint
    X As Single
    Y As Single
End Type

Private Type MyPair
    p1 As MyPoint
    p2 As MyPoint
End Type

Sub Main()
Dim points() As MyPoint, i As Long, BF As MyPair, d As Single, Nb As Long
Dim T#
Randomize Timer
    Nb = 10
    Do
        ReDim points(1 To Nb)
        For i = 1 To Nb
            points(i).X = Rnd * Nb
            points(i).Y = Rnd * Nb
        Next
        d = 1000000000000#
T = Timer
        BF = BruteForce(points, d)
        Debug.Print "For " & Nb & " points, runtime : " & Timer - T & " sec."
        Debug.Print "point 1 : X:" & BF.p1.X & " Y:" & BF.p1.Y
        Debug.Print "point 2 : X:" & BF.p2.X & " Y:" & BF.p2.Y
        Debug.Print "dist : " & d
        Debug.Print "--------------------------------------------------"
        Nb = Nb * 10
    Loop While Nb <= 10000
End Sub

Private Function BruteForce(p() As MyPoint, mindist As Single) As MyPair
Dim i As Long, j As Long, d As Single, ClosestPair As MyPair
    For i = 1 To UBound(p) - 1
        For j = i + 1 To UBound(p)
            d = Dist(p(i), p(j))
            If d < mindist Then
                mindist = d
                ClosestPair.p1 = p(i)
                ClosestPair.p2 = p(j)
            End If
        Next
    Next
    BruteForce = ClosestPair
End Function

Private Function Dist(p1 As MyPoint, p2 As MyPoint) As Single
    Dist = Sqr((p1.X - p2.X) ^ 2 + (p1.Y - p2.Y) ^ 2)
End Function