Skip to content

Instantly share code, notes, and snippets.

@attatrol
Last active June 1, 2020 13:50
Show Gist options
  • Save attatrol/567c1927882d7bff295451874c715762 to your computer and use it in GitHub Desktop.
Save attatrol/567c1927882d7bff295451874c715762 to your computer and use it in GitHub Desktop.
/**
* D. База в джунглях
*/
//#define DEBUG
#include <assert.h>
#include <cmath>
#include <iostream>
#ifdef DEBUG
#include <fstream>
#endif
#include <vector>
using value_t = long long;
class KahanAccumulator
{
private:
double value_;
double delta_;
public:
KahanAccumulator() : value_(0), delta_(0)
{
}
double getValue() const
{
return value_;
}
void add(double summand)
{
double a = summand - delta_;
double b = value_ + a;
delta_ = (b - value_) - a;
value_ = b;
}
};
struct Point
{
double x_;
double y_;
};
struct HalfPlane
{
value_t a_;
value_t b_;
value_t c_;
};
static constexpr value_t MAX_COORD = 200000001;
bool belongsToHalfPlane(const Point& p, const HalfPlane& hp)
{
return hp.a_ * p.x_ + hp.b_ * p.y_ + hp.c_ >= 0;
}
bool calcIntersection(const HalfPlane& hp0, const HalfPlane& hp1, Point& intersect)
{
if (hp0.a_ == hp1.a_ && hp0.b_ == hp1.b_)
{
return false;
}
value_t detAB = hp0.a_ * hp1.b_ - hp0.b_ * hp1.a_;
intersect.x_ = 1.0 * (hp0.b_ * hp1.c_ - hp0.c_ * hp1.b_) / detAB;
intersect.y_ = 1.0 * (hp0.c_ * hp1.a_ - hp0.a_ * hp1.c_) / detAB;
return true;
}
bool pointIsBetween(Point& p0, Point& p1, Point& pBetween)
{
return ((p0.x_ <= pBetween.x_ && pBetween.x_ < p1.x_) || (p0.x_ >= pBetween.x_ && pBetween.x_ > p1.x_))
&& ((p0.y_ <= pBetween.y_ && pBetween.y_ < p1.y_) || (p0.y_ >= pBetween.y_ && pBetween.y_ > p1.y_));
}
std::pair<std::vector<Point>, std::vector<HalfPlane>> cut(
const std::vector<Point>& polygon,
const std::vector<HalfPlane>& polygonLines,
const HalfPlane& hp)
{
std::vector<Point> newPolygon;
std::vector<HalfPlane> newPolygonLines;
for (std::size_t i = 0; i < polygon.size() - 1; ++i)
{
bool pBelongs = belongsToHalfPlane(polygon[i], hp);
bool pNextBelongs = belongsToHalfPlane(polygon[i + 1], hp);
if (pBelongs)
{
newPolygon.push_back(polygon[i]);
newPolygonLines.push_back(polygonLines[i]);
}
if (pBelongs && !pNextBelongs)
{
Point pIntersect;
calcIntersection(hp, polygonLines[i], pIntersect);
newPolygon.push_back(pIntersect);
newPolygonLines.push_back(hp);
}
if (!pBelongs && pNextBelongs)
{
Point pIntersect;
calcIntersection(hp, polygonLines[i], pIntersect);
newPolygon.push_back(pIntersect);
newPolygonLines.push_back(polygonLines[i]);
}
}
{
std::size_t maxIndex = polygon.size() - 1;
bool pBelongs = belongsToHalfPlane(polygon[maxIndex], hp);
bool pNextBelongs = belongsToHalfPlane(polygon[0], hp);
if (pBelongs)
{
newPolygon.push_back(polygon[maxIndex]);
newPolygonLines.push_back(polygonLines[maxIndex]);
}
if (pBelongs && !pNextBelongs)
{
Point pIntersect;
calcIntersection(hp, polygonLines[maxIndex], pIntersect);
newPolygon.push_back(pIntersect);
newPolygonLines.push_back(hp);
}
if (!pBelongs && pNextBelongs)
{
Point pIntersect;
calcIntersection(hp, polygonLines[maxIndex], pIntersect);
newPolygon.push_back(pIntersect);
newPolygonLines.push_back(polygonLines[maxIndex]);
}
}
return std::make_pair(newPolygon, newPolygonLines);
}
double calcConvexHullSquare(const std::vector<Point>& hull)
{
const Point a = hull[0];
KahanAccumulator square;
for (std::size_t i = 1; i < hull.size() - 1; ++i)
{
const Point& b = hull[i];
const Point& c = hull[i + 1];
const double xab = b.x_ - a.x_;
const double yab = b.y_ - a.y_;
const double xac = c.x_ - a.x_;
const double yac = c.y_ - a.y_;
const double abcSquare = 0.5 * (xab * yac - yab * xac);
assert(abcSquare > 0);
square.add(abcSquare);
}
return square.getValue();
}
HalfPlane getCanonicalLineEquation(const value_t x0, const value_t y0, const value_t x1, const value_t y1)
{
HalfPlane result;
result.a_ = y0 - y1;
result.b_ = x1 - x0;
result.c_ = x0 * y1 - y0 * x1;
return result;
}
bool continuousCut(std::vector<Point> polygon, std::vector<HalfPlane> polygonLines, std::size_t continuousCutSize)
{
const std::size_t size = polygon.size();
std::vector<HalfPlane> cutLines(size);
for (std::size_t i = 0; i < size; ++i)
{
std::size_t j = i + continuousCutSize + 1;
if (j > size - 1)
{
j -= size;
}
cutLines[i] = getCanonicalLineEquation(polygon[i].x_, polygon[i].y_, polygon[j].x_, polygon[j].y_);
}
for (std::size_t i = 0; i < size; ++i)
{
auto [newPolygon, newPolygonLines] = cut(polygon, polygonLines, cutLines[i]);
polygon = newPolygon;
polygonLines = newPolygonLines;
if (polygon.size() < 3)
{
return false;
}
}
return polygon.size() >= 3;
}
int main()
{
#ifdef DEBUG
std::ifstream cin("input.txt");
#else
using std::cin;
std::ios::sync_with_stdio(false);
cin.tie(nullptr);
std::cout.tie(nullptr);
#endif
std::cout.precision(12);
std::size_t pointCount;
cin >> pointCount;
std::vector<Point> polygon(pointCount);
for (std::size_t i = 0; i < pointCount; ++i)
{
cin >> polygon[pointCount - i - 1].x_ >> polygon[pointCount - i - 1].y_;
}
std::vector<HalfPlane> polygonLines(pointCount);
for (std::size_t i = 0; i < pointCount - 1; ++i)
{
polygonLines[i] = getCanonicalLineEquation(polygon[i].x_, polygon[i].y_, polygon[i + 1].x_, polygon[i + 1].y_);
}
{
polygonLines[pointCount - 1] = getCanonicalLineEquation(polygon[pointCount - 1].x_, polygon[pointCount - 1].y_, polygon[0].x_, polygon[0].y_);
}
std::size_t continuousCutSize = 1;
while(continuousCut(polygon, polygonLines, continuousCutSize))
{
++continuousCutSize;
}
std::cout << continuousCutSize << '\n';
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment