#include <cassert> #include <iostream> #include <algorithm> #include <complex> #include <tuple> #include <cmath> #include <iomanip> using namespace std; using T = long double; using pt = complex<T>; #define FOR(i, n) for(int i = 0, __n = n; i < __n; i++) // #define DEBUG true #ifdef DEBUG #define LOG(x) cerr << x << endl; #else #define LOG(x) #endif #ifndef DEBUG #define DEBUG false #endif const int MAXN = 100; int n; T dot(pt v, pt w) {return (conj(v) * w).real();} T cross(pt v, pt w) {return (conj(v) * w).imag();} struct line { pt p, q; line() {} line(pt p, pt q) : p(p), q(q) {} pt vec() const { return q - p; } T c() const { return cross(vec(), p); } friend ostream& operator<<(ostream& os, const line& dt); } V[MAXN]; ostream& operator<<(ostream& os, const line& l) { os << l.p << "->" << l.q; return os; } T orient(line ab, pt c) {return cross(ab.q - ab.p,c - ab.p);} bool half(pt p) { assert(p != pt(0)); return p.imag() > 0 || (p.imag() == 0 && p.real() < 0); } bool angularCompare(pt v, pt w) { return make_tuple(half(v), 0) < make_tuple(half(w), cross(v, w)); } bool angularCompareLine(const line & a, const line & b) { return angularCompare(a.vec(), b.vec()); } pt inter(const line & l1, const line & l2) { T d = cross(l1.vec(), l2.vec()); if (d == 0) { LOG("NO INTER " << l1 << " " << l2); cout << 0 << endl; exit(0); } // assert (d != 0); return (l2.vec() * l1.c() - l1.vec() * l2.c()) / d; } bool parallel(const line & l1, const line & l2) { return cross(l1.vec(), l2.vec()) == 0; } bool isCandidate(line a) { int online = 0; FOR(i, n) { T o1 = orient(a, V[i].p); T o2 = orient(a, V[i].q); if (o1 < 0 && o2 < 0) { return false; } else { if (o1 == 0 && o2 <= 0 || o2 == 0 && o1 <= 0) { online++; } } } if (online < 2) return false; return true; } int main() { cin >> n; FOR (i, n) { int a, b; cin >> a >> b; V[i].p = pt(a, b); cin >> a >> b; V[i].q = pt(a, b); } vector<line> candidates; FOR (i, n) { FOR (j, n) if(i != j) { line t[] = { line(V[i].p, V[j].p), line(V[i].p, V[j].q), line(V[i].q, V[j].p), line(V[i].q, V[j].q), }; FOR(k, 4) { if (isCandidate(t[k])) { LOG("CANDIDATE: " << t[k]); candidates.push_back(t[k]); } else { LOG("NOT CANDIDATE: " << t[k]); } } } } sort(candidates.begin(), candidates.end(), angularCompareLine); vector<line> bounds(1, candidates[0]); LOG(bounds.back() << " INIT"); for (int i = 1; i < candidates.size(); i++) { const line & l = candidates[i]; if (DEBUG) { cerr << endl << " " << i << " > " << l << " < " << endl; FOR(i, bounds.size()) { cerr << bounds[i] << " "; } cerr << endl; } if (parallel(l, bounds.back())) { LOG("> PARALLEL " << l << " " << bounds.back()); if (orient(bounds.back(), l.p) <= 0) { LOG(l << " PARALLEL IGNORE"); //Ignoruj, jezeli linia jest po zlej stronie. continue; } else if(bounds.size() == 1) { LOG(l << " PARALLEL REPLACE SINGLE"); //Jezeli mamy jedyną linię, to zastąp. bounds[0] = l; continue; } // w przeciwnym wypadku usuwamy ostatnią linię i dodajemy normalnie LOG("! " << bounds.back() << " PARALLEL POP"); bounds.pop_back(); } while (bounds.size() > 1) { const line& l1 = bounds[bounds.size()-2]; const line& l2 = bounds[bounds.size()-1]; pt p2 = inter(l2, l); if (orient(l1, p2) <= 0) { LOG("! " << bounds.back() << " POP"); bounds.pop_back(); } else { break; } } LOG(l << " PUSH"); bounds.push_back(l); } int start = 0; while (bounds.size() > start + 2) { if (orient(bounds[bounds.size()-2], inter(bounds[start], bounds.back())) <= 0) { LOG("! " << bounds.back() << " POP OVERLAP BACK"); bounds.pop_back(); } else if (orient(bounds.back(), inter(bounds[start], bounds[start+1])) <= 0) { LOG("! " << bounds[start] << " POP OVERLAP FRONT"); start++; } else { break; } } bounds.erase(bounds.begin(), bounds.begin() + start); vector<pt> nodes; FOR(i, bounds.size()) { nodes.push_back(inter(bounds[i], bounds[(i+1) % bounds.size()])); } T area = 0; FOR(i, nodes.size()) { area += cross(nodes[i], nodes[(i+1) % nodes.size()]); } FOR(i, nodes.size()) { LOG(nodes[i]); } if (area < 0 && nodes.size() == 3) area = 0; cout << std::setprecision(12) << std::fixed << area/2 << endl; return 0; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 | #include <cassert> #include <iostream> #include <algorithm> #include <complex> #include <tuple> #include <cmath> #include <iomanip> using namespace std; using T = long double; using pt = complex<T>; #define FOR(i, n) for(int i = 0, __n = n; i < __n; i++) // #define DEBUG true #ifdef DEBUG #define LOG(x) cerr << x << endl; #else #define LOG(x) #endif #ifndef DEBUG #define DEBUG false #endif const int MAXN = 100; int n; T dot(pt v, pt w) {return (conj(v) * w).real();} T cross(pt v, pt w) {return (conj(v) * w).imag();} struct line { pt p, q; line() {} line(pt p, pt q) : p(p), q(q) {} pt vec() const { return q - p; } T c() const { return cross(vec(), p); } friend ostream& operator<<(ostream& os, const line& dt); } V[MAXN]; ostream& operator<<(ostream& os, const line& l) { os << l.p << "->" << l.q; return os; } T orient(line ab, pt c) {return cross(ab.q - ab.p,c - ab.p);} bool half(pt p) { assert(p != pt(0)); return p.imag() > 0 || (p.imag() == 0 && p.real() < 0); } bool angularCompare(pt v, pt w) { return make_tuple(half(v), 0) < make_tuple(half(w), cross(v, w)); } bool angularCompareLine(const line & a, const line & b) { return angularCompare(a.vec(), b.vec()); } pt inter(const line & l1, const line & l2) { T d = cross(l1.vec(), l2.vec()); if (d == 0) { LOG("NO INTER " << l1 << " " << l2); cout << 0 << endl; exit(0); } // assert (d != 0); return (l2.vec() * l1.c() - l1.vec() * l2.c()) / d; } bool parallel(const line & l1, const line & l2) { return cross(l1.vec(), l2.vec()) == 0; } bool isCandidate(line a) { int online = 0; FOR(i, n) { T o1 = orient(a, V[i].p); T o2 = orient(a, V[i].q); if (o1 < 0 && o2 < 0) { return false; } else { if (o1 == 0 && o2 <= 0 || o2 == 0 && o1 <= 0) { online++; } } } if (online < 2) return false; return true; } int main() { cin >> n; FOR (i, n) { int a, b; cin >> a >> b; V[i].p = pt(a, b); cin >> a >> b; V[i].q = pt(a, b); } vector<line> candidates; FOR (i, n) { FOR (j, n) if(i != j) { line t[] = { line(V[i].p, V[j].p), line(V[i].p, V[j].q), line(V[i].q, V[j].p), line(V[i].q, V[j].q), }; FOR(k, 4) { if (isCandidate(t[k])) { LOG("CANDIDATE: " << t[k]); candidates.push_back(t[k]); } else { LOG("NOT CANDIDATE: " << t[k]); } } } } sort(candidates.begin(), candidates.end(), angularCompareLine); vector<line> bounds(1, candidates[0]); LOG(bounds.back() << " INIT"); for (int i = 1; i < candidates.size(); i++) { const line & l = candidates[i]; if (DEBUG) { cerr << endl << " " << i << " > " << l << " < " << endl; FOR(i, bounds.size()) { cerr << bounds[i] << " "; } cerr << endl; } if (parallel(l, bounds.back())) { LOG("> PARALLEL " << l << " " << bounds.back()); if (orient(bounds.back(), l.p) <= 0) { LOG(l << " PARALLEL IGNORE"); //Ignoruj, jezeli linia jest po zlej stronie. continue; } else if(bounds.size() == 1) { LOG(l << " PARALLEL REPLACE SINGLE"); //Jezeli mamy jedyną linię, to zastąp. bounds[0] = l; continue; } // w przeciwnym wypadku usuwamy ostatnią linię i dodajemy normalnie LOG("! " << bounds.back() << " PARALLEL POP"); bounds.pop_back(); } while (bounds.size() > 1) { const line& l1 = bounds[bounds.size()-2]; const line& l2 = bounds[bounds.size()-1]; pt p2 = inter(l2, l); if (orient(l1, p2) <= 0) { LOG("! " << bounds.back() << " POP"); bounds.pop_back(); } else { break; } } LOG(l << " PUSH"); bounds.push_back(l); } int start = 0; while (bounds.size() > start + 2) { if (orient(bounds[bounds.size()-2], inter(bounds[start], bounds.back())) <= 0) { LOG("! " << bounds.back() << " POP OVERLAP BACK"); bounds.pop_back(); } else if (orient(bounds.back(), inter(bounds[start], bounds[start+1])) <= 0) { LOG("! " << bounds[start] << " POP OVERLAP FRONT"); start++; } else { break; } } bounds.erase(bounds.begin(), bounds.begin() + start); vector<pt> nodes; FOR(i, bounds.size()) { nodes.push_back(inter(bounds[i], bounds[(i+1) % bounds.size()])); } T area = 0; FOR(i, nodes.size()) { area += cross(nodes[i], nodes[(i+1) % nodes.size()]); } FOR(i, nodes.size()) { LOG(nodes[i]); } if (area < 0 && nodes.size() == 3) area = 0; cout << std::setprecision(12) << std::fixed << area/2 << endl; return 0; } |