Найти комбинации средних элементов в векторе

У меня есть вектор vector<Points>list_of_points;, содержащий точки A B C D A. Я хочу найти все возможные комбинации вектора, сохраняя два внешних элемента в одном и том же месте. Например, A B C D A -- A B D C A -- A C B D A -- A C D B A -- A D B C A -- A D C B A. Любые советы о том, как я могу это сделать?

Я делаю это, потому что каждая точка имеет координату x, y. Я пытаюсь найти кратчайшее расстояние, чтобы перейти ко всем элементам и вернуться к исходному элементу. Я думаю установить минимальное расстояние равным первой комбинации A B C D A, и сравнить все остальные комбинации

//pseudocode
min distance = distance of A B C D A

while(there are still combinations){
   find another combinations of the vector.
   if that distance is smaller than min distance, make it the new min distance 
   save the path in a vector
}

Если нужно, вот моя реализация

#include <cmath>
#include <string>
#include <vector>
#include <iostream>

using namespace std;

class Point
{
  private:
    int m_x;
    int m_y;
    string m_name;

  public:
    Point(int x, int y, string name)
      : m_x(x), m_y(y), m_name(name)
    {}
    
    Point(){};
    
    int getX() const {return m_x;}
    void setX(int x) {m_x=x;}

    int getY() const {return m_y;}
    void setY(int y) {m_y=y;}

    string getName() const {return m_name;}
    
    
    float getDistance(Point &other);

    string toString() const;

    void printPoint() const;

    // used for printing Point using << operator. For example:
    // Point p(1,2,"A");
    // cout << p << endl;
    friend ostream& operator<<(ostream &os, const Point &p);

};

class ListOfPoints
{ 
  private:
    int elements;
    
  public:
    vector<Point>sorted_list;
    vector<Point>unsorted_list;
    
    void Unsorted_add(Point &newPt);
    void Sorted_add(Point &newPt);
    void Create_unsorted();
    void Sort_list();
    
    void set_elements(int n);
    int get_elements();
    
    
    ListOfPoints();

    // adds a new point to the end of the list
    void addPoint(Point &newPt);
    
    // prints the list of points
    void printList() const;
    
    // draws the points
    void draw() const;

};

string Point::toString() const{
  // examples how to create string from small parts
  string str(m_name);
  str += " = (";
  str += std::to_string(m_x);
  str.append(",").append(std::to_string(m_y)).append(")");
  return str;
} 

float Point::getDistance(Point &other){
  float x1 = float(this->getX());
        cout << "this->x = "<< this->getX() <<endl;
        cout << "this->y = "<<this->getY() <<endl;
        float y1 = float(this->getY());
        float x2 = float(other.getX());
        float y2 = float(other.getY());
        //cout << "x = " << x2 << endl;
        //cout << "y = " << y2 << endl;
        float dist = sqrt( pow(x2-x1,2) + pow(y2-y1,2) );
        cout << "dist = " << dist << endl;
        return dist;
}
void Point::printPoint() const{
  cout << toString() << endl;
}

// used for printing Point using << operator.
// For example, the following code will work
// Point origin(0,0,'O');
// cout << origin;
ostream& operator<<(ostream &os, const Point &p) {
  return os << p.toString();
}

ListOfPoints::ListOfPoints() {

}


void ListOfPoints::Sorted_add(Point &newPt)  {
  sorted_list.push_back(newPt);
}

void ListOfPoints::Unsorted_add(Point &newPt)  {
  unsorted_list.push_back(newPt);
}


void ListOfPoints::set_elements(int n){
  elements = n;
}

int ListOfPoints::get_elements(){
  return this->elements;
}

void ListOfPoints::Create_unsorted(){
  int x;
  int y;
  string name;
  
  cout << "Enter the Number of elements" << endl;
  cin >> elements;
  for(int i = 0; i<elements; i++){
    cout << "Enter the name of the element: " << endl;
    cin >> name;
    cout <<"Enter the x value" << endl;
    cin >> x;
    cout <<"Enter they y vlaue" << endl;
    cin >> y;
    Point p(x,y,name);
    unsorted_list.push_back(p);
    
  }

  cout << elements << endl;
  return;
}

person CS_12319    schedule 06.12.2020    source источник
comment
будет nPn количество результатов: где n - размер вектора - 2, а nPn означает перестановку. Вам, вероятно, придется найти способ ограничить его, иначе будет много результатов.   -  person WARhead    schedule 06.12.2020
comment
В стандартной библиотеке есть функция поиска перестановок, называемая std::next_permutation. Вы можете просто дать ему итераторы для второго и последнего элемента в качестве диапазона для перестановки, а затем вручную добавить первое и последнее значение.   -  person nick    schedule 06.12.2020
comment
softwareengineering.stackexchange.com/questions/315836/ просмотрите это в поисках лучшего алгоритма, поскольку грубая сила может быть невозможна для более длинных векторов, грубая сила имеет сложность O (n!)   -  person WARhead    schedule 06.12.2020


Ответы (1)


Судя по вашему описанию, следующая программа демонстрирует, чего вы пытаетесь достичь, используя std::next_permutation :

#include <algorithm>
#include <string>
#include <iostream>

int main()
{
    std::string test = "ABCDA";

    // sort the items after the beginning and before the end of the sequence
    std::sort(test.begin() + 1, std::prev(test.end()));
    do
    {
        std::cout << test << "\n";
      // permute the middle elements
    } while (std::next_permutation(test.begin() + 1, std::prev(test.end())));
}

Выход:

ABCDA
ABDCA
ACBDA
ACDBA
ADBCA
ADCBA

Чтобы расширить это до вашего класса Point, вам нужно каким-то образом отсортировать средние точки, а затем применить ту же логику, используя std::next_permutation.

Вот небольшой пример:

#include <algorithm>
#include <vector>
#include <iostream>

struct Point
{
    int m_x;
    int m_y;
    int get_x() const { return m_x; }
    int get_y() const { return m_y; }
    Point(int x = 0, int y = 0) : m_x(x), m_y(y) {}
};
    
int main()
{
    std::vector<Point> test = {{0,0},{1,2},{2,1},{3,6},{2,7},{10,10}};
    std::vector<std::vector<Point>> results;
    auto sorter = [](const Point& p1, const Point& p2) { return std::tie(p1.m_x, p1.m_y) < std::tie(p2.m_x, p2.m_y); };
    
    // sort the items after the beginning and before the end of the sequence
    std::sort(test.begin() + 1, std::prev(test.end()), sorter);
    do
    {
        results.push_back(test);
    } while (std::next_permutation(test.begin() + 1, std::prev(test.end()), sorter));
    
    for (auto& r : results)
    {
        for (auto& p : r)
           std::cout << "{" << p.get_x() << "," << p.get_y() << ") ";
        std::cout << "\n";
    }
}

Выход:

{0,0) {1,2) {2,1) {2,7) {3,6) {10,10) 
{0,0) {1,2) {2,1) {3,6) {2,7) {10,10) 
{0,0) {1,2) {2,7) {2,1) {3,6) {10,10) 
{0,0) {1,2) {2,7) {3,6) {2,1) {10,10) 
{0,0) {1,2) {3,6) {2,1) {2,7) {10,10) 
{0,0) {1,2) {3,6) {2,7) {2,1) {10,10) 
{0,0) {2,1) {1,2) {2,7) {3,6) {10,10) 
{0,0) {2,1) {1,2) {3,6) {2,7) {10,10) 
{0,0) {2,1) {2,7) {1,2) {3,6) {10,10) 
{0,0) {2,1) {2,7) {3,6) {1,2) {10,10) 
{0,0) {2,1) {3,6) {1,2) {2,7) {10,10) 
{0,0) {2,1) {3,6) {2,7) {1,2) {10,10) 
{0,0) {2,7) {1,2) {2,1) {3,6) {10,10) 
{0,0) {2,7) {1,2) {3,6) {2,1) {10,10) 
{0,0) {2,7) {2,1) {1,2) {3,6) {10,10) 
{0,0) {2,7) {2,1) {3,6) {1,2) {10,10) 
{0,0) {2,7) {3,6) {1,2) {2,1) {10,10) 
{0,0) {2,7) {3,6) {2,1) {1,2) {10,10) 
{0,0) {3,6) {1,2) {2,1) {2,7) {10,10) 
{0,0) {3,6) {1,2) {2,7) {2,1) {10,10) 
{0,0) {3,6) {2,1) {1,2) {2,7) {10,10) 
{0,0) {3,6) {2,1) {2,7) {1,2) {10,10) 
{0,0) {3,6) {2,7) {1,2) {2,1) {10,10) 
{0,0) {3,6) {2,7) {2,1) {1,2) {10,10) 

Я выбрал критерии сортировки на основе значений x и y, при этом значения x сравниваются в первую очередь.

person PaulMcKenzie    schedule 06.12.2020
comment
Я немного смущен, что вы подразумеваете под сортировкой. Откуда мне знать, по каким критериям сортировать. Разве std::next_permuatation не нуждается в каких-то критериях? Я попробовал и получил длинный список ошибок. - person CS_12319; 06.12.2020
comment
Отсортируйте его по x, а затем по y. Смотрите редактирование. - person PaulMcKenzie; 06.12.2020