Cod sursa(job #1057919)

Utilizator a_h1926Heidelbacher Andrei a_h1926 Data 14 decembrie 2013 20:35:09
Problema Triangulare Scor 100
Compilator cpp Status done
Runda Arhiva ICPC Marime 3.71 kb
#include <cstdio>
#include <cassert>

#include <vector>
#include <algorithm>

using namespace std;

class Point {
  public:
    int x, y;

    Point(const int _x = 0, const int _y = 0):
      x(_x),
      y(_y) {}

    bool operator==(const Point &other) const {
        return (x == other.x && y == other.y);
    }
};

inline int Det(const Point &p1, const Point &p2, const Point &p3) {
    return p1.x * p2.y + p2.x * p3.y + p3.x * p1.y - p1.x * p3.y - p2.x * p1.y - p3.x * p2.y;
}

class Segment {
  public:
    Point e1, e2;

    Segment(const Point _e1, const Point _e2):
      e1(_e1),
      e2(_e2) {
        if (e1.y > e2.y)
            swap(e1, e2);
    }

    static bool OpenIntersection(const Segment &s1, const Segment &s2) {
        if (s1.e1 == s1.e2 || s2.e1 == s2.e2)
            return false;
        if (Det(s1.e1, s1.e2, s2.e1) == 0 && Det(s1.e1, s1.e2, s2.e2) == 0) {
            if (OpenIntervalIntersection(s1.e1.x, s1.e2.x, s2.e1.x, s2.e2.x))
                return true;
            if (OpenIntervalIntersection(s1.e1.y, s1.e2.y, s2.e1.y, s2.e2.y))
                return true;
            return false;
        }
        return (1LL * Det(s1.e1, s1.e2, s2.e1) * Det(s1.e1, s1.e2, s2.e2) < 0 && 1LL * Det(s2.e1, s2.e2, s1.e1) * Det(s2.e1, s2.e2, s1.e2) < 0);
    }

  private:
    static bool OpenIntervalIntersection(int x1, int x2, int y1, int y2) {
        if (x1 > x2)
            swap(x1, x2);
        if (y1 > y2)
            swap(y1, y2);
        if (x1 > y1) {
            swap(x1, y1);
            swap(x2, y2);
        }
        return y1 < x2;
    }
};

class Polygon {
  public:
    vector<Segment> edges;

    Polygon():
      edges(vector<Segment>()) {}

    Polygon(const vector<Point> &points) {
        for (int i = 0; i < int(points.size()); ++i)
            edges.push_back(Segment(points[i], points[(i + 1) % int(points.size())]));
    }

    bool IsInside(const Point &p) const {
        int intersect = 0;
        for (const auto &segment: edges)
            if (segment.e1.y < p.y && p.y <= segment.e2.y && Det(segment.e1, segment.e2, p) < 0)
                ++intersect;
        return intersect % 2 == 1;
    }
};

vector<Point> Points;
Polygon P;
int N;
vector< pair<int, int> > Triangulation;

inline bool CheckSegment(const Segment &edge) {
    for (const auto &e: P.edges)
        if (Segment::OpenIntersection(e, edge))
            return false;
    for (const auto &e: Triangulation)
        if (Segment::OpenIntersection(Segment(Points[e.first], Points[e.second]), edge))
            return false;
    return P.IsInside(Point((edge.e1.x + edge.e2.x) / 2, (edge.e1.y + edge.e2.y) / 2));
}

void Solve() {
    Triangulation = vector< pair<int, int> >();
    for (int i = 0; i < N; ++i)
        for (int j = (i + 2) % N; (j + 1) % N != i; j = (j + 1) % N)
            if (CheckSegment(Segment(Points[i], Points[j])))
                Triangulation.push_back(make_pair(i, j));
    sort(Triangulation.begin(), Triangulation.end());
}

void Read() {
    assert(scanf("%d", &N) == 1);
    Points = vector<Point>(N);
    for (int i = 0; i < N; ++i) {
        assert(scanf("%d %d", &Points[i].x, &Points[i].y) == 2);
        Points[i].x *= 2;
        Points[i].y *= 2;
    }
    P = Polygon(Points);
}

void Print() {
    for (const auto &segment: Triangulation)
        printf("%d %d\n", segment.first, segment.second);
}

int main() {
    assert(freopen("triangulare.in", "r", stdin));
    assert(freopen("triangulare.out", "w", stdout));
    int testCount;
    assert(scanf("%d", &testCount) == 1);
    for (; testCount > 0; --testCount) {
        Read();
        Solve();
        Print();
    }
    return 0;
}