Выполнение простого поиска в глубину со спиральным поисковым соседством с возвратом на тупики может быть эффективным для замкнутых многоугольников без дырок. Я приложил простое решение. Если в вашем полигоне есть дыры, особенно если их много, вам нужно взглянуть на более мощные решения, предназначенные для общей задачи коммивояжера.
Я включил несколько тестовых данных (5x5 2D векторов) и переключаемая настройка #define BIAS
, которая заставит поиск двигаться как можно дальше к одному углу, а затем повернуть к следующему углу. В некоторых случаях это быстрее, но в целом оставить поиск беспристрастным, вероятно, быстрее, и я оставил его неопределенным по умолчанию в коде ниже.
#include <iostream>
#include <vector>
using namespace std;
#define TEST3
#ifdef TEST1
bool matrixInit[] = {
0, 0, 1, 0, 0,
0, 1, 1, 1, 0,
1, 1, 1, 1, 1,
0, 1, 1, 1, 0,
0, 0, 1, 0, 0
};
std::pair<int, int> startPoint(0, 2);
int trueCount = 13;
#elif defined(TEST2)
bool matrixInit[] = {
1, 1, 1, 1, 1,
1, 1, 1, 1, 1,
0, 1, 1, 1, 1,
0, 1, 1, 1, 1,
0, 1, 1, 1, 1
};
std::pair<int, int> startPoint(0, 2);
int trueCount = 22;
#elif defined(TEST3)
bool matrixInit[] = {
1, 0, 0, 0, 1,
1, 1, 0, 1, 1,
1, 1, 0, 1, 1,
1, 1, 1, 1, 1,
1, 1, 1, 1, 1
};
std::pair<int, int> startPoint(0, 4);
int trueCount = 20;
#endif
//#define BIAS
std::vector<std::vector<bool>> matrixVec;
std::vector<std::vector<std::pair<int, int>>> lastNode;
std::vector<std::pair<int, int>> path;
int visitedCount = 0;
int main() {
matrixVec.resize(5);
lastNode.resize(5);
for (int i = 0; i < 5; ++i) {
matrixVec[i].resize(5);
lastNode[i].resize(5);
}
for (int y = 0; y < 5; ++y) {
for (int x = 0; x < 5; ++x) {
matrixVec[y][x] = matrixInit[y * 5 + x];
lastNode[y][x] = std::pair<int, int>(-1, -1);
}
}
//Important! Up, right, down, left spiral
static int neighX[]{0, 1, 0, -1};
static int neighY[]{-1, 0, 1, 0};
static int bias = 0;
path.push_back(startPoint);
matrixVec[startPoint.first][startPoint.second] = 0;
++visitedCount;
std::pair<int, int> currentPoint(startPoint);
bool lastFoundVisited = true;
int biasLimit = 4;
#ifdef BIAS
biasLimit = 2;
#endif
while (visitedCount < trueCount) {
bool foundUnvisited = false;
for (int i = 0; i < biasLimit; ++i) {
int n = (i + bias) % 4;
int nextY = currentPoint.first + neighY[n];
int nextX = currentPoint.second + neighX[n];
if (nextY >= matrixVec.size() || nextX >= matrixVec[0].size() || nextY < 0 || nextX < 0) {
continue;
}
if (matrixVec[nextY][nextX]) {
lastFoundVisited = true;
foundUnvisited = true;
++visitedCount;
matrixVec[nextY][nextX] = false;
lastNode[nextY][nextX] = currentPoint;
currentPoint = std::pair<int, int>(nextY, nextX);
path.push_back(currentPoint);
break;
}
}
if (foundUnvisited) {
continue;
}
#ifdef BIAS
if (lastFoundVisited) {
lastFoundVisited = false;
bias = (bias + 1) % 4;
continue;
}
#endif
//Surrounded by matrix boundaries or previously visited nodes. Need to backtrack
currentPoint = lastNode[currentPoint.first][currentPoint.second];
path.push_back(currentPoint);
}
cout << "SIZE: " << path.size() << endl;
for (int i = 0; i < path.size(); ++i) {
cout << path[i].first << ", " << path[i].second << endl;
}
return 0;
}