-1

I am trying to understand and implement a solution for the Closest/farthest pair of points problem.

On https://en.wikipedia.org/wiki/Closest_pair_of_points_problem there is an example of the brute-force approach:

minDist = infinity
for i = 1 to length(P) - 1 do
    for j = i + 1 to length(P) do
        let p = P[i], q = P[j]
        if dist(p, q) < minDist  then
            minDist = dist(p, q)
            closestPair = (p, q)
return closestPair

The thing is that I can't figure a way of doing the same in C++.
I don't want to return anything. I want to store the pair of structs into something that I can later output.

I've commented a mock-up implementation that does not work.

struct punct
{
    int x, y;
    float distanta(punct z)
    {
        float dx = z.x - x, dy = z.y - y;
        return std::sqrt(dx * dx + dy * dy);
    }
};

    float min = v->distanta(*(v + 1));
    float max = min;
    // punct close, far;

    for (int i = 0; i < n - 1; i++)
        for (int j = i + 1; j < n; j++)
        {
            if (((v + i)->distanta(*(v + j))) > max)
            {
                max = ((v + i)->distanta(*(v + j)));
                // far = (*(v+i), *(v+j));
            }
            if (((v + i)->distanta(*(v + j))) < min)
            {
                min = ((v + i)->distanta(*(v + j)));
                // close = (*(v+i), *(v+j));
            }
        }

    cout.precision(4);
    cout << min << " " << max;
    // cout << far; // this doesn't work;

From these two pieces of code I want to output something like "The farthest two points are (x, y) and (a, b).".

Also, how do I handle the case where there are more than one close or far pair ? Meaning that there are two or more smallest/largest distances.

Jorje12
  • 415
  • 1
  • 3
  • 14
  • Does this answer your question? [Returning multiple values from a C++ function](https://stackoverflow.com/questions/321068/returning-multiple-values-from-a-c-function) – Aykhan Hagverdili Mar 08 '21 at 13:57
  • No. I don't see a way of using `std::pair` or `std:tuple` in my code. I don't return anything inside the `for` loops. I only want to store a pair of structs inside something to be able to output them. – Jorje12 Mar 08 '21 at 14:03
  • To be honest, it's not clear what your question is. I thought you're somehow trying to return 2 values from a function. Please add a [mcve]. – Aykhan Hagverdili Mar 08 '21 at 14:05
  • @AyxanHaqverdili I have edited the question. I hope it makes more sense now. – Jorje12 Mar 08 '21 at 14:07
  • 3
    `cout << far; // this doesn't work;` -> maxbe this one helps? https://stackoverflow.com/questions/2981836/how-can-i-use-cout-myclass C++ doesn't know how to output a `punct`. – Lukas-T Mar 08 '21 at 14:10
  • @Jorje12 `closestPair = (p, q)` looks a lot like something `std::pair` could do. – Aykhan Hagverdili Mar 08 '21 at 14:11

3 Answers3

0

If you think you'll only return one pair of results, then have your function return a std::pair<punct, punct> which you would create as follows:

return std::make_pair(close, far);

But as you say you envisage the possibility of "two or more smallest/largest distances", I would encapsulate the return type in a struct that has a collection of pairs

struct NearFarPunct
{
    std::vector<std::pair<punct, punct>> pairs;
};

which you could create as follows:

NearFarPunct ret;
ret.pairs.push_back(std::make_pair(close, far));
// ... and subsequent
return ret;

I suggest encapsulation in a struct else the function return type as a vector gets hard to read.

acraig5075
  • 10,588
  • 3
  • 31
  • 50
  • I understand how my question is not clear. I don't have a function that returns and I don't want one. I simply want to store a pair of `punct` structs and output them in some way. Doing this `std::pair close, far;` and `far = std::make_pair(*(v + i), *(v + j));` left me with no idea on how to output the pair. I should get something like: "The farthest two points are (x, y) and (a, b)." – Jorje12 Mar 08 '21 at 14:45
  • This answer no longer makes sense because the question has changed from pairing up two struct values to custom ostream outputting of a struct – acraig5075 Mar 08 '21 at 17:20
  • Actually no. I've resolved it without modifying the `ostream`output. Check my answer. – Jorje12 Mar 09 '21 at 11:12
0

I think the main problem, (apart from not defining v ) in the mock up, is that 'close' and 'far' variables need to be a type representing a pair of puncts rather than just one punct and assignment of the struct requires curly braces, not brackets.

I used a structure punct_pair encapsulating a pair of punct's, so now punct_pair is a unique class and so you can provide an overload of the stream output operator for it as below:

I didn't address the case of more than one close or far pair. You could simply use a std::vector and output in a for loop I think.


//for sqrt
#include <cmath>  
#include <iostream>

struct punct
{
    int x, y;
    float distanta(punct z)
    {
        float dx = z.x - x, dy = z.y - y;
        return std::sqrt(dx * dx + dy * dy);
    }
};

//stream outut for punct
std::ostream& operator << ( std::ostream & os, punct const & pt)
{ 
  return os <<  '(' << pt. x<< ',' << pt.y << ')'; 
}

//pair of points
struct punct_pair{
  punct puncts[2];
};

//stream outut for punct_pair
std::ostream& operator << ( std::ostream & os, punct_pair const & pts)
{ 
   return os << '[' << *(pts.puncts + 0) << ',' << *(pts.puncts + 1) << ']'; 
}

using namespace std;

int main()
{
   punct v[] ={{0,0},{1,1},{1,3},{-1,10}, {-1,11},{20,-4}};

   float min = v->distanta(*(v + 1));
   float max = min;
//### changed to punct_pair ### 
   punct_pair close; 
   punct_pair far;
//##############################
   int n = std::size(v);
   for (int i = 0; i < n - 1; i++)
      for (int j = i + 1; j < n; j++)
      {
         auto const d = (v + i)->distanta(*(v + j));
         if (d > max)
         {
            max = d;
            far = {*(v+i), *(v+j)};
         }
         if (d < min)
         {
           min = d;
           close = {*(v+i), *(v+j)};
         }
      }

   cout.precision(4);
   cout << min << " " << max << '\n';
   cout << close << " " << far << '\n';
}
QuatCoder
  • 232
  • 1
  • 5
0

Based on every comment and answer here I have formulated the following solution:

int main()
{
    ifstream fisier("p4.txt");

    int n;
    punct *v;
    citire(fisier, &v, n);

    float min = v->distanta(*(v + 1));
    float max = min;
    std::pair<punct, punct> aproape, departe;

    for (int i = 0; i < n - 1; i++)
        for (int j = i + 1; j < n; j++)
        {
            if (((v + i)->distanta(*(v + j))) > max)
            {
                max = ((v + i)->distanta(*(v + j)));
                departe = std::make_pair(*(v + i), *(v + j));
            }
            if (((v + i)->distanta(*(v + j))) < min)
            {
                min = ((v + i)->distanta(*(v + j)));
                aproape = std::make_pair(*(v + i), *(v + j));
            }
        }

    cout.precision(4);
    // cout << min << " " << max << endl;

    cout << "Farthest pair: {(" << departe.first.x << ", " << departe.first.y << "), ("
         << departe.second.x << ", " << departe.second.y << ")}";
    cout << endl;
    cout << "Closest pair: {(" << aproape.first.x << ", " << aproape.first.y << "), ("
         << aproape.second.x << ", " << aproape.second.y << ")}";

    cout << endl
         << endl;
    delete[] v;
}

This doesn't solve the issue of having more than one pair of closest or farthest points, but it's more than enough for what I needed.

Jorje12
  • 415
  • 1
  • 3
  • 14