#include <array>
#include <chrono>
#include <iostream>
struct point {
int x;
int y;
};
template<std::size_t N>
bool create_polygon_jit(std::array<point, N>& points, int n, int target_n, int gridsize, int curr_area, int& min_area, std::array<point, N>& soln)
{
if (n >= 3)
{
int x1 = points[n - 3].x - points[n - 2].x, y1 = points[n - 3].y - points[n - 2].y;
int x2 = points[n - 1].x - points[n - 2].x, y2 = points[n - 1].y - points[n - 2].y;
if (x1 * y2 - x2 * y1 <= 0) // Angle > 180
return false;
if (x1 * x2 + y1 * y2 > 0) // Angle >= 90
return false;
if (points[0].x == 0 and points[n - 1].x == 0)
return true;
int add_area = points[n - 1].x * points[n - 2].y - points[n - 1].y * points[n - 2].x;
if (add_area <= 0)
return true;
curr_area += add_area;
if (curr_area >= min_area)
return true;
if (n == target_n)
{
min_area = curr_area;
soln = points;
return true;
}
int min_i = std::max(0, points[N - 1].x - 3);
int max_i = std::min(gridsize, points[N - 1].x + 4);
int min_j = std::max(-gridsize / 2, points[n - 1].y - 3);
int max_j = std::min(gridsize / 2, points[n - 1].y + 4);
if (x2 > 0)
{
if (y2 > 0)
{
if (x2 > y2)
{
for (int j = min_j; j < max_j; j++)
{
for (int i = max_i - 1; i > min_i - 1; i--)
{
points[n].x = i;
points[n].y = j;
if (!create_polygon_jit(points, n + 1, target_n, gridsize, curr_area, min_area, soln))
break;
}
if (points[n].x == max_i - 1)
break;
}
}
else
{
for (int j = max_j - 1; j > min_j - 1; j--)
{
for (int i = max_i - 1; i > min_i - 1; i--)
{
points[n].x = i;
points[n].y = j;
if (!create_polygon_jit(points, n + 1, target_n, gridsize, curr_area, min_area, soln))
break;
}
if (points[n].x == max_i - 1)
break;
}
}
}
else
{
if (x2 > -y2)
{
for (int i = max_i - 1; i > min_i - 1; i--)
{
for (int j = min_j; j < max_j; j++)
{
points[n].x = i;
points[n].y = j;
if (!create_polygon_jit(points, n + 1, target_n, gridsize, curr_area, min_area, soln))
break;
}
if (points[n].y == min_j)
break;
}
}
else
{
for (int i = min_i; i < max_i; i++)
{
for (int j = min_j; j < max_j; j++)
{
points[n].x = i;
points[n].y = j;
;
if (!create_polygon_jit(points, n + 1, target_n, gridsize, curr_area, min_area, soln))
break;
}
if (points[n].y == min_j)
break;
}
}
}
}
else
{
if (y2 > 0)
{
if (-x2 > y2)
{
for (int i = min_i; i < max_i; i++)
{
for (int j = max_j - 1; j > min_j - 1; j--)
{
points[n].x = i;
points[n].y = j;
if (!create_polygon_jit(points, n + 1, target_n, gridsize, curr_area, min_area, soln))
break;
}
if (points[n].y == max_j - 1)
break;
}
}
else
{
for (int i = max_i; i > min_i - 1; i--)
{
for (int j = max_j - 1; j > min_j - 1; j--)
{
points[n].x = i;
points[n].y = j;
if (!create_polygon_jit(points, n + 1, target_n, gridsize, curr_area, min_area, soln))
break;
}
if (points[n].y == max_j - 1)
break;
}
}
}
else
{
if (-x2 > -y2)
{
for (int j = max_j - 1; j > min_j - 1; j--)
{
for (int i = min_i; i < max_i; i++)
{
points[n].x = i;
points[n].y = j;
if (!create_polygon_jit(points, n + 1, target_n, gridsize, curr_area, min_area, soln))
break;
}
if (points[n].x == min_i)
break;
}
}
else
{
for (int j = min_j; j < max_j; j++)
{
for (int i = min_i; i < max_i; i++)
{
points[n].x = i;
points[n].y = j;
if (!create_polygon_jit(points, n + 1, target_n, gridsize, curr_area, min_area, soln))
break;
}
if (points[n].x == min_i)
break;
}
}
}
}
}
else
{
int min_i = std::max(0, points[n - 1].x - 3);
int max_i = std::min(gridsize, points[n - 1].x + 4);
int min_j = std::max(-gridsize / 2, points[n - 1].y - 3);
int max_j = std::min(gridsize / 2, points[n - 1].y + 4);
for (int i = min_i; i < max_i; i++)
{
for (int j = min_j; j < max_j; j++)
{
points[n].x = i;
points[n].y = j;
create_polygon_jit(points, n + 1, target_n, gridsize, curr_area, min_area, soln);
}
}
}
points[n].x = 0;
points[n].y = 0;
return true;
}
int crossproduct(const point& p0, const point& p1, const point& p2) {
const int x1 = p1.x - p0.x, y1 = p1.y - p0.y;
const int x2 = p2.x - p0.x, y2 = p2.y - p0.y;
return x1 * y2 - y1 * x2;
}
template<std::size_t N>
int double_area(std::array<point, N>& points) {
int sum = 0;
for (int i = 2; i < N; i++)
sum += crossproduct(points[0], points[i - 1], points[i]);
return abs(sum);
}
int main() {
using namespace std::chrono;
auto t1 = steady_clock::now();
const int n = 14;
std::array<point, n> points{};
int gridSize = 9;
int minArea = gridSize * gridSize;
std::array<point, n> result;
create_polygon_jit(points, 1, n, gridSize, 0, minArea, result);
std::cout << "Result: ";
for (point& p : result)
std::cout << p.x << ", " << p.y << " ";
std::cout << "\nArea: " << double_area(result) << "\n";
auto t2 = steady_clock::now();
auto time_span = duration_cast<duration<double>>(t2 - t1);
std::cout << "Time:" << time_span.count() << " seconds.\n";
}
I2luY2x1ZGUgPGFycmF5PgojaW5jbHVkZSA8Y2hyb25vPgojaW5jbHVkZSA8aW9zdHJlYW0+CgpzdHJ1Y3QgcG9pbnQgewoJaW50IHg7CglpbnQgeTsKfTsKCnRlbXBsYXRlPHN0ZDo6c2l6ZV90IE4+CmJvb2wgY3JlYXRlX3BvbHlnb25faml0KHN0ZDo6YXJyYXk8cG9pbnQsIE4+JiBwb2ludHMsIGludCBuLCBpbnQgdGFyZ2V0X24sIGludCBncmlkc2l6ZSwgaW50IGN1cnJfYXJlYSwgaW50JiBtaW5fYXJlYSwgc3RkOjphcnJheTxwb2ludCwgTj4mIHNvbG4pIAp7CglpZiAobiA+PSAzKQoJewoJCWludCB4MSA9IHBvaW50c1tuIC0gM10ueCAtIHBvaW50c1tuIC0gMl0ueCwgeTEgPSBwb2ludHNbbiAtIDNdLnkgLSBwb2ludHNbbiAtIDJdLnk7CgkJaW50IHgyID0gcG9pbnRzW24gLSAxXS54IC0gcG9pbnRzW24gLSAyXS54LCB5MiA9IHBvaW50c1tuIC0gMV0ueSAtIHBvaW50c1tuIC0gMl0ueTsKCQlpZiAoeDEgKiB5MiAtIHgyICogeTEgPD0gMCkgLy8gQW5nbGUgPiAxODAKCQkJcmV0dXJuIGZhbHNlOwoJCWlmICh4MSAqIHgyICsgeTEgKiB5MiA+IDApICAvLyBBbmdsZSA+PSA5MAoJCQlyZXR1cm4gZmFsc2U7CgkJaWYgKHBvaW50c1swXS54ID09IDAgYW5kIHBvaW50c1tuIC0gMV0ueCA9PSAwKQoJCQlyZXR1cm4gdHJ1ZTsKCgkJaW50IGFkZF9hcmVhID0gcG9pbnRzW24gLSAxXS54ICogcG9pbnRzW24gLSAyXS55IC0gcG9pbnRzW24gLSAxXS55ICogcG9pbnRzW24gLSAyXS54OwoJCWlmIChhZGRfYXJlYSA8PSAwKQoJCQlyZXR1cm4gdHJ1ZTsKCgkJY3Vycl9hcmVhICs9IGFkZF9hcmVhOwoJCWlmIChjdXJyX2FyZWEgPj0gbWluX2FyZWEpCgkJCXJldHVybiB0cnVlOwoKCQlpZiAobiA9PSB0YXJnZXRfbikKCQl7CgkJCW1pbl9hcmVhID0gY3Vycl9hcmVhOwoJCQlzb2xuID0gcG9pbnRzOwoJCQlyZXR1cm4gdHJ1ZTsKCQl9CgoJCWludCBtaW5faSA9IHN0ZDo6bWF4KDAsIHBvaW50c1tOIC0gMV0ueCAtIDMpOwoJCWludCBtYXhfaSA9IHN0ZDo6bWluKGdyaWRzaXplLCBwb2ludHNbTiAtIDFdLnggKyA0KTsKCgkJaW50IG1pbl9qID0gc3RkOjptYXgoLWdyaWRzaXplIC8gMiwgcG9pbnRzW24gLSAxXS55IC0gMyk7CgkJaW50IG1heF9qID0gc3RkOjptaW4oZ3JpZHNpemUgLyAyLCBwb2ludHNbbiAtIDFdLnkgKyA0KTsKCgkJaWYgKHgyID4gMCkKCQl7CgkJCWlmICh5MiA+IDApCgkJCXsKCQkJCWlmICh4MiA+IHkyKQoJCQkJewoJCQkJCWZvciAoaW50IGogPSBtaW5fajsgaiA8IG1heF9qOyBqKyspCgkJCQkJewoJCQkJCQlmb3IgKGludCBpID0gbWF4X2kgLSAxOyBpID4gbWluX2kgLSAxOyBpLS0pCgkJCQkJCXsKCQkJCQkJCXBvaW50c1tuXS54ID0gaTsKCQkJCQkJCXBvaW50c1tuXS55ID0gajsKCQkJCQkJCWlmICghY3JlYXRlX3BvbHlnb25faml0KHBvaW50cywgbiArIDEsIHRhcmdldF9uLCBncmlkc2l6ZSwgY3Vycl9hcmVhLCBtaW5fYXJlYSwgc29sbikpCgkJCQkJCQkJYnJlYWs7CgkJCQkJCX0KCQkJCQkJaWYgKHBvaW50c1tuXS54ID09IG1heF9pIC0gMSkKCQkJCQkJCWJyZWFrOwoKCQkJCQl9CgkJCQl9CgkJCQllbHNlCgkJCQl7CgkJCQkJZm9yIChpbnQgaiA9IG1heF9qIC0gMTsgaiA+IG1pbl9qIC0gMTsgai0tKQoJCQkJCXsKCQkJCQkJZm9yIChpbnQgaSA9IG1heF9pIC0gMTsgaSA+IG1pbl9pIC0gMTsgaS0tKQoJCQkJCQl7CgkJCQkJCQlwb2ludHNbbl0ueCA9IGk7CgkJCQkJCQlwb2ludHNbbl0ueSA9IGo7CgoJCQkJCQkJaWYgKCFjcmVhdGVfcG9seWdvbl9qaXQocG9pbnRzLCBuICsgMSwgdGFyZ2V0X24sIGdyaWRzaXplLCBjdXJyX2FyZWEsIG1pbl9hcmVhLCBzb2xuKSkKCQkJCQkJCQlicmVhazsKCQkJCQkJfQoJCQkJCQlpZiAocG9pbnRzW25dLnggPT0gbWF4X2kgLSAxKQoJCQkJCQkJYnJlYWs7CgkJCQkJfQoJCQkJfQoJCQl9CgkJCWVsc2UKCQkJewoJCQkJaWYgKHgyID4gLXkyKQoJCQkJewoJCQkJCWZvciAoaW50IGkgPSBtYXhfaSAtIDE7IGkgPiBtaW5faSAtIDE7IGktLSkKCQkJCQl7CgkJCQkJCWZvciAoaW50IGogPSBtaW5fajsgaiA8IG1heF9qOyBqKyspCgkJCQkJCXsKCQkJCQkJCXBvaW50c1tuXS54ID0gaTsKCQkJCQkJCXBvaW50c1tuXS55ID0gajsKCgkJCQkJCQlpZiAoIWNyZWF0ZV9wb2x5Z29uX2ppdChwb2ludHMsIG4gKyAxLCB0YXJnZXRfbiwgZ3JpZHNpemUsIGN1cnJfYXJlYSwgbWluX2FyZWEsIHNvbG4pKQoJCQkJCQkJCWJyZWFrOwoJCQkJCQl9CgkJCQkJCWlmIChwb2ludHNbbl0ueSA9PSBtaW5faikKCQkJCQkJCWJyZWFrOwoJCQkJCX0KCQkJCX0KCQkJCWVsc2UKCQkJCXsKCQkJCQlmb3IgKGludCBpID0gbWluX2k7IGkgPCBtYXhfaTsgaSsrKQoJCQkJCXsKCQkJCQkJZm9yIChpbnQgaiA9IG1pbl9qOyBqIDwgbWF4X2o7IGorKykKCQkJCQkJewoJCQkJCQkJcG9pbnRzW25dLnggPSBpOwoJCQkJCQkJcG9pbnRzW25dLnkgPSBqOwoJCQkJCQkJOwoJCQkJCQkJaWYgKCFjcmVhdGVfcG9seWdvbl9qaXQocG9pbnRzLCBuICsgMSwgdGFyZ2V0X24sIGdyaWRzaXplLCBjdXJyX2FyZWEsIG1pbl9hcmVhLCBzb2xuKSkKCQkJCQkJCQlicmVhazsKCQkJCQkJfQoJCQkJCQlpZiAocG9pbnRzW25dLnkgPT0gbWluX2opCgkJCQkJCQlicmVhazsKCQkJCQl9CgkJCQl9CgkJCX0KCQl9CgkJZWxzZQoJCXsKCQkJaWYgKHkyID4gMCkKCQkJewoJCQkJaWYgKC14MiA+IHkyKQoJCQkJewoJCQkJCWZvciAoaW50IGkgPSBtaW5faTsgaSA8IG1heF9pOyBpKyspCgkJCQkJewoJCQkJCQlmb3IgKGludCBqID0gbWF4X2ogLSAxOyBqID4gbWluX2ogLSAxOyBqLS0pCgkJCQkJCXsKCQkJCQkJCXBvaW50c1tuXS54ID0gaTsKCQkJCQkJCXBvaW50c1tuXS55ID0gajsKCgkJCQkJCQlpZiAoIWNyZWF0ZV9wb2x5Z29uX2ppdChwb2ludHMsIG4gKyAxLCB0YXJnZXRfbiwgZ3JpZHNpemUsIGN1cnJfYXJlYSwgbWluX2FyZWEsIHNvbG4pKQoJCQkJCQkJCWJyZWFrOwoJCQkJCQl9CgkJCQkJCWlmIChwb2ludHNbbl0ueSA9PSBtYXhfaiAtIDEpCgkJCQkJCQlicmVhazsKCQkJCQl9CgkJCQl9CgkJCQllbHNlCgkJCQl7CgkJCQkJZm9yIChpbnQgaSA9IG1heF9pOyBpID4gbWluX2kgLSAxOyBpLS0pCgkJCQkJewoJCQkJCQlmb3IgKGludCBqID0gbWF4X2ogLSAxOyBqID4gbWluX2ogLSAxOyBqLS0pCgkJCQkJCXsKCQkJCQkJCXBvaW50c1tuXS54ID0gaTsKCQkJCQkJCXBvaW50c1tuXS55ID0gajsKCgkJCQkJCQlpZiAoIWNyZWF0ZV9wb2x5Z29uX2ppdChwb2ludHMsIG4gKyAxLCB0YXJnZXRfbiwgZ3JpZHNpemUsIGN1cnJfYXJlYSwgbWluX2FyZWEsIHNvbG4pKQoJCQkJCQkJCWJyZWFrOwoJCQkJCQl9CgkJCQkJCWlmIChwb2ludHNbbl0ueSA9PSBtYXhfaiAtIDEpCgkJCQkJCQlicmVhazsKCQkJCQl9CgkJCQl9CgkJCX0KCQkJZWxzZQoJCQl7CgkJCQlpZiAoLXgyID4gLXkyKQoJCQkJewoJCQkJCWZvciAoaW50IGogPSBtYXhfaiAtIDE7IGogPiBtaW5faiAtIDE7IGotLSkKCQkJCQl7CgkJCQkJCWZvciAoaW50IGkgPSBtaW5faTsgaSA8IG1heF9pOyBpKyspCgkJCQkJCXsKCQkJCQkJCXBvaW50c1tuXS54ID0gaTsKCQkJCQkJCXBvaW50c1tuXS55ID0gajsKCgkJCQkJCQlpZiAoIWNyZWF0ZV9wb2x5Z29uX2ppdChwb2ludHMsIG4gKyAxLCB0YXJnZXRfbiwgZ3JpZHNpemUsIGN1cnJfYXJlYSwgbWluX2FyZWEsIHNvbG4pKQoJCQkJCQkJCWJyZWFrOwoJCQkJCQl9CgkJCQkJCWlmIChwb2ludHNbbl0ueCA9PSBtaW5faSkKCQkJCQkJCWJyZWFrOwoJCQkJCX0KCQkJCX0KCQkJCWVsc2UKCQkJCXsKCQkJCQlmb3IgKGludCBqID0gbWluX2o7IGogPCBtYXhfajsgaisrKQoJCQkJCXsKCQkJCQkJZm9yIChpbnQgaSA9IG1pbl9pOyBpIDwgbWF4X2k7IGkrKykKCQkJCQkJewoJCQkJCQkJcG9pbnRzW25dLnggPSBpOwoJCQkJCQkJcG9pbnRzW25dLnkgPSBqOwoKCQkJCQkJCWlmICghY3JlYXRlX3BvbHlnb25faml0KHBvaW50cywgbiArIDEsIHRhcmdldF9uLCBncmlkc2l6ZSwgY3Vycl9hcmVhLCBtaW5fYXJlYSwgc29sbikpCgkJCQkJCQkJYnJlYWs7CgkJCQkJCX0KCQkJCQkJaWYgKHBvaW50c1tuXS54ID09IG1pbl9pKQoJCQkJCQkJYnJlYWs7CgkJCQkJfQoJCQkJfQoKCQkJfQoJCX0KCX0KCWVsc2UKCXsKCQlpbnQgbWluX2kgPSBzdGQ6Om1heCgwLCBwb2ludHNbbiAtIDFdLnggLSAzKTsKCQlpbnQgbWF4X2kgPSBzdGQ6Om1pbihncmlkc2l6ZSwgcG9pbnRzW24gLSAxXS54ICsgNCk7CgoJCWludCBtaW5faiA9IHN0ZDo6bWF4KC1ncmlkc2l6ZSAvIDIsIHBvaW50c1tuIC0gMV0ueSAtIDMpOwoJCWludCBtYXhfaiA9IHN0ZDo6bWluKGdyaWRzaXplIC8gMiwgcG9pbnRzW24gLSAxXS55ICsgNCk7CgoJCWZvciAoaW50IGkgPSBtaW5faTsgaSA8IG1heF9pOyBpKyspCgkJewoJCQlmb3IgKGludCBqID0gbWluX2o7IGogPCBtYXhfajsgaisrKQoJCQl7CgkJCQlwb2ludHNbbl0ueCA9IGk7CgkJCQlwb2ludHNbbl0ueSA9IGo7CgkJCQljcmVhdGVfcG9seWdvbl9qaXQocG9pbnRzLCBuICsgMSwgdGFyZ2V0X24sIGdyaWRzaXplLCBjdXJyX2FyZWEsIG1pbl9hcmVhLCBzb2xuKTsKCQkJfQoJCX0KCX0KCXBvaW50c1tuXS54ID0gMDsKCXBvaW50c1tuXS55ID0gMDsKCXJldHVybiB0cnVlOwp9CgppbnQgY3Jvc3Nwcm9kdWN0KGNvbnN0IHBvaW50JiBwMCwgY29uc3QgcG9pbnQmIHAxLCBjb25zdCBwb2ludCYgcDIpIHsKCWNvbnN0IGludCB4MSA9IHAxLnggLSBwMC54LCB5MSA9IHAxLnkgLSBwMC55OwoJY29uc3QgaW50IHgyID0gcDIueCAtIHAwLngsIHkyID0gcDIueSAtIHAwLnk7CglyZXR1cm4geDEgKiB5MiAtIHkxICogeDI7Cn0KCnRlbXBsYXRlPHN0ZDo6c2l6ZV90IE4+CmludCBkb3VibGVfYXJlYShzdGQ6OmFycmF5PHBvaW50LCBOPiYgcG9pbnRzKSB7CglpbnQgc3VtID0gMDsKCWZvciAoaW50IGkgPSAyOyBpIDwgTjsgaSsrKQoJCXN1bSArPSBjcm9zc3Byb2R1Y3QocG9pbnRzWzBdLCBwb2ludHNbaSAtIDFdLCBwb2ludHNbaV0pOwoJcmV0dXJuIGFicyhzdW0pOwp9CgppbnQgbWFpbigpIHsKCXVzaW5nIG5hbWVzcGFjZSBzdGQ6OmNocm9ubzsKCWF1dG8gdDEgPSBzdGVhZHlfY2xvY2s6Om5vdygpOwoKCWNvbnN0IGludCBuID0gMTQ7CglzdGQ6OmFycmF5PHBvaW50LCBuPiBwb2ludHN7fTsKCglpbnQgZ3JpZFNpemUgPSA5OwoJaW50IG1pbkFyZWEgPSBncmlkU2l6ZSAqIGdyaWRTaXplOwoKCXN0ZDo6YXJyYXk8cG9pbnQsIG4+IHJlc3VsdDsKCWNyZWF0ZV9wb2x5Z29uX2ppdChwb2ludHMsIDEsIG4sIGdyaWRTaXplLCAwLCBtaW5BcmVhLCByZXN1bHQpOwoKCXN0ZDo6Y291dCA8PCAiUmVzdWx0OiAiOwoJZm9yIChwb2ludCYgcCA6IHJlc3VsdCkKCQlzdGQ6OmNvdXQgPDwgcC54IDw8ICIsICIgPDwgcC55IDw8ICIgICI7CglzdGQ6OmNvdXQgPDwgIlxuQXJlYTogIiA8PCBkb3VibGVfYXJlYShyZXN1bHQpIDw8ICJcbiI7CgoJYXV0byB0MiA9IHN0ZWFkeV9jbG9jazo6bm93KCk7CglhdXRvIHRpbWVfc3BhbiA9IGR1cmF0aW9uX2Nhc3Q8ZHVyYXRpb248ZG91YmxlPj4odDIgLSB0MSk7CglzdGQ6OmNvdXQgPDwgIlRpbWU6IiA8PCB0aW1lX3NwYW4uY291bnQoKSA8PCAiIHNlY29uZHMuXG4iOwp9