Tricky Ricky is a world-famous magician. He even claims that he can overcome the laws of physics and geometry.
In his latest trick he covers a w × h rectangle with n triangles fully contained within the rectangle. Sounds easy? But what would you say if he told you that the total area of those triangles is smaller than w·h?
You are of that kind of people that are not very fun at parties and magic shows, so you want to prove him that this is impossible. Given a description of n triangles, find any point of the rectangle which does not belong to any triangle interior or border.
The first line of the input contains three integers n, w and h (1 ≤ n ≤ 100 000, 1 ≤ w, h ≤ 10 000) — the number of triangles and the dimensions of the rectangle.
The following n lines contain descriptions of triangle vertices. Each line contains six integers xi, 1, yi, 1, xi, 2, yi, 2, xi, 3 and yi, 3(0 ≤ xi, j ≤ w, 0 ≤ yi, j ≤ h). It is guaranteed that all given triangles are non-degenerate, and the total area of triangles is smaller than w·h.
Print two real numbers x and y (0 ≤ x ≤ w, 0 ≤ y ≤ h) defining the coordinates of a point that lies strictly outside of all of the triangles. The numbers should be printed as decimal fractions with at most 9 digits after decimal point. Note that usage of exponential format is not allowed. Your answer will be considered correct if the given point does not belong to any triangle interior or border. Please, note that your answer will be verified with no absolute or relative tolerance.
It is guaranteed (by Euclid and some other guys) that such point always exists.
5 4 3
0 0 3 0 0 2
3 3 0 1 0 3
1 1 3 1 2 3
3 0 4 0 4 3
4 3 3 2 4 1
1.1 1.6
An illustration for the sample is given below.
思路:题目保证了三角形面积和不超过矩形面积。四分矩形,必有一子矩形中面积超过该矩形与所有三角形面积交的和,求三角形和矩形面积交用的半平面交板子。四分一定次数后在子矩形内随机取点判断是否合法。
程序中的trick:四个子矩形中随机选顺序判断,若子矩形面积差值超过大矩形面积差值四分之一,则进入该子矩形;
四分过程中及时排除掉与当前矩形相交面积为0的三角形。
随机选点之前也排除掉不可能在其上的三角形。
不加这几个优化会T,调了92发才过,可能我的半平面交比较挫吧。
1 #include <iostream> 2 #include <fstream> 3 #include <sstream> 4 #include <cstdlib> 5 #include <cstdio> 6 #include <cmath> 7 #include <string> 8 #include <cstring> 9 #include <algorithm> 10 #include <queue> 11 #include <stack> 12 #include <vector> 13 #include <set> 14 #include <map> 15 #include <list> 16 #include <iomanip> 17 #include <cctype> 18 #include <cassert> 19 #include <bitset> 20 #include <ctime> 21 22 using namespace std; 23 24 #define pau system("pause") 25 #define ll long long 26 #define pii pair<int, int> 27 #define pb push_back 28 #define pli pair<ll, int> 29 #define pil pair<int, ll> 30 #define clr(a, x) memset(a, x, sizeof(a)) 31 32 const double pi = acos(-1.0); 33 const int INF = 0x3f3f3f3f; 34 const int MOD = 1e9 + 7; 35 const double EPS = 1e-14; 36 37 /* 38 #include <ext/pb_ds/assoc_container.hpp> 39 #include <ext/pb_ds/tree_policy.hpp> 40 using namespace __gnu_pbds; 41 #define TREE tree<pli, null_type, greater<pli>, rb_tree_tag, tree_order_statistics_node_update> 42 TREE T; 43 */ 44 45 46 #define Double double 47 48 int n; 49 Double w, h; 50 struct Point { 51 Double x, y; 52 Point () {} 53 Point(Double x, Double y) : x(x), y(y) {} 54 Point operator - (const Point &p) const { 55 return Point(x - p.x, y - p.y); 56 } 57 Double operator ^ (const Point &p) const { 58 return x * p.y - y * p.x; 59 } 60 void input() { 61 double tx, ty; 62 scanf("%lf%lf", &tx, &ty); 63 x = tx, y = ty; 64 } 65 }; 66 struct Line { 67 Point s, e; 68 double k; 69 Line () {} 70 Line (Point _s, Point _e) { 71 s = _s, e = _e; 72 k = atan2(e.y - s.y, e.x - s.x); 73 } 74 Point operator & (const Line &b) const { 75 Point res = s; 76 double t = ((s - b.s) ^ (b.s - b.e)) / ((s - e) ^ (b.s - b.e)); 77 res.x += (e.x - s.x) * t; 78 res.y += (e.y - s.y) * t; 79 return res; 80 } 81 }; 82 83 //左侧有效 84 bool HPIcmp(Line a, Line b) { 85 if (fabs(a.k - b.k) > EPS) return a.k < b.k; 86 return ((a.s - b.s) ^ (b.e - b.s)) < 0; 87 } 88 89 bool onRightPL(Point p, Line l) { 90 return ((p - l.s) ^ (l.e - l.s)) > EPS; 91 } 92 93 Line Q[22510]; 94 95 inline void HPI(Line line[], int n, Point res[], int &resn) { 96 sort(line, line + n, HPIcmp); 97 int tot = 0; 98 for (int i = 1; i < n; ++i) { 99 if (fabs(line[i].k - line[i - 1].k) > EPS) { 100 line[++tot] = line[i]; 101 } 102 } 103 int head = 0, tail = 1; 104 Q[0] = line[0]; Q[1] = line[1]; 105 for (int i = 2; i <= tot; ++i) { 106 if (fabs((Q[tail].e - Q[tail].s) ^ (Q[tail - 1].e - Q[tail - 1].s)) < EPS || 107 fabs((Q[head].e - Q[head].s) ^ (Q[head + 1].e - Q[head + 1].s)) < EPS) 108 return; 109 while (head < tail && onRightPL(Q[tail] & Q[tail - 1], line[i])) --tail; 110 while (head < tail && onRightPL(Q[head] & Q[head + 1], line[i])) ++head; 111 Q[++tail] = line[i]; 112 } 113 while (head < tail && onRightPL(Q[tail] & Q[tail - 1], Q[head])) --tail; 114 while (head < tail && onRightPL(Q[head] & Q[head + 1], Q[tail])) ++head; 115 if (tail <= head + 1) return; 116 for (int i = head; i < tail; ++i) { 117 res[resn++] = Q[i] & Q[i + 1]; 118 } 119 if (head < tail - 1) res[resn++] = Q[tail] & Q[head]; 120 } 121 inline double cal_S(Point p[], int resn) { 122 double ans = 0; 123 for (int i = 0; i < resn; ++i) { 124 ans += p[i] ^ p[(i + 1) % resn]; 125 } 126 return 0.5 * fabs(ans); 127 } 128 struct Tran { 129 Point p[3]; 130 void input() { 131 for (int i = 0; i < 3; ++i) { 132 p[i].input(); 133 } 134 } 135 void modify() { 136 double wx = (p[0].x + p[1].x + p[2].x) / 3; 137 double wy = (p[0].y + p[1].y + p[2].y) / 3; 138 if (onRightPL(Point(wx, wy), Line(p[0], p[1]))) { 139 swap(p[0], p[2]); 140 } 141 } 142 inline double S(double x1, double x2, double y1, double y2) { 143 Line l[11]; 144 for (int i = 0; i < 3; ++i) { 145 l[i] = Line(p[i], p[(i + 1) % 3]); 146 } 147 l[3] = Line(Point(x2, 0), Point(x2, 1)); 148 l[4] = Line(Point(x1, 1), Point(x1, 0)); 149 l[5] = Line(Point(0, y1), Point(1, y1)); 150 l[6] = Line(Point(1, y2), Point(0, y2)); 151 Point res[17]; int resn = 0; 152 HPI(l, 7, res, resn); 153 return cal_S(res, resn); 154 } 155 } t[100015]; 156 bool inTran(Point p, Tran t) { 157 Double res1 = (p - t.p[0]) ^ (p - t.p[1]); 158 Double res2 = (p - t.p[1]) ^ (p - t.p[2]); 159 Double res3 = (p - t.p[2]) ^ (p - t.p[0]); 160 if (fabs(res1) < EPS || fabs(res2) < EPS || fabs(res3) < EPS) return true; 161 return res1 < -EPS && res2 < -EPS && res3 < -EPS || 162 res1 > EPS && res2 > EPS && res3 > EPS; 163 } 164 bool vis[100015], tvis[100015]; 165 bool ok(Point p) { 166 for (int i = 1; i <= n; ++i) { 167 if (vis[i]) continue; 168 if (inTran(p, t[i])) return false; 169 } 170 return true; 171 } 172 double ok(double x1, double x2, double y1, double y2) { 173 double s = 0; 174 for (int i = 1; i <= n; ++i) { 175 if (vis[i]) continue; 176 double x = t[i].S(x1, x2, y1, y2); 177 if (x < EPS) tvis[i] = 1; 178 s += x; 179 } 180 return (y2 - y1) * (x2 - x1) - s; 181 } 182 const int dir[4][2] = { 183 1, 1, 0, 1, 184 1, 0, 0, 0 185 }; 186 bool online(Point p1, Point p2, Point p3) { 187 double res = (p2 - p1) ^ (p3 - p1); 188 if (fabs(res) > EPS) return false; 189 double x1 = min(p2.x, p3.x), x2 = max(p2.x, p3.x); 190 double y1 = min(p2.y, p3.y), y2 = max(p2.y, p3.y); 191 return x1 <= p2.x && p2.x <= x2 && y1 <= p2.y && p2.y <= y2; 192 } 193 bool ok(int id, double x1, double x2, double y1, double y2) { 194 if (t[id].S(x1, x2, y1, y2) > EPS) return false; 195 for (int i = 0; i < 3; ++i) { 196 if (online(t[id].p[i], Point(x1, y1), Point(x1, y2))) return false; 197 if (online(t[id].p[i], Point(x1, y1), Point(x2, y1))) return false; 198 if (online(t[id].p[i], Point(x2, y2), Point(x1, y2))) return false; 199 if (online(t[id].p[i], Point(x2, y2), Point(x2, y1))) return false; 200 if (online(Point(x1, y1), t[id].p[i], t[id].p[(i + 1) % 3])) return false; 201 if (online(Point(x1, y2), t[id].p[i], t[id].p[(i + 1) % 3])) return false; 202 if (online(Point(x2, y1), t[id].p[i], t[id].p[(i + 1) % 3])) return false; 203 if (online(Point(x2, y2), t[id].p[i], t[id].p[(i + 1) % 3])) return false; 204 } 205 return true; 206 } 207 int main() { 208 clock_t start = clock(); 209 srand((int)time(NULL)); 210 scanf("%d", &n); 211 cin >> w >> h; 212 for (int i = 1; i <= n; ++i) { 213 t[i].input(); 214 t[i].modify(); 215 } 216 Double sx = 0, sy = 0, lx = w * 0.5, ly = h * 0.5; 217 double deltas = w * h; 218 for (int i = 1; i <= n; ++i) { 219 deltas += ((t[i].p[2] - t[i].p[0]) ^ (t[i].p[1] - t[i].p[0])) / 2; 220 } 221 if (99978 == n) { 222 //printf("%.12f ", deltas); 223 } 224 for (int rep = 1; rep <= 20; ++rep) { 225 double tmp[4]; 226 int id; 227 int dd[4] = {0, 1, 2, 3}; 228 random_shuffle(dd, dd + 4); 229 for (int i = 3; ~i; --i) { 230 double tx = sx + lx * dir[dd[i]][0]; 231 double ty = sy + ly * dir[dd[i]][1]; 232 for (int i = 1; i <= n; ++i) tvis[i] = 0; 233 tmp[i] = ok(tx, tx + lx, ty, ty + ly); 234 if (tmp[i] >= 0.25 * deltas - EPS) { 235 id = dd[i]; 236 for (int i = 1; i <= n; ++i) { 237 vis[i] |= tvis[i]; 238 } 239 break; 240 } 241 } 242 //int id = rand() % 4; 243 for (int i = 0; i < 4; ++i) { 244 //if (tmp[i] > tmp[id]) id = i; 245 } 246 sx = sx + dir[id][0] * lx; 247 sy = sy + dir[id][1] * ly; 248 lx *= 0.5, ly *= 0.5; 249 deltas *= 0.25; 250 } 251 clock_t end = clock(); 252 if (99978 == n) { 253 //return !printf("%.6f ", (double)(end - start) / CLOCKS_PER_SEC); 254 } 255 for (int i = 1; i <= n; ++i) { 256 vis[i] = ok(i, sx, sx + lx * 2, sy, sy + ly * 2); 257 } 258 double Lx = lx, Ly = ly; 259 for (int rep = 1; rep <= 100000; ++rep) { 260 Double x = 1.0 * rand() / RAND_MAX * Lx * 2 + sx; 261 Double y = 1.0 * rand() / RAND_MAX * Ly * 2 + sy; 262 if (ok(Point(x, y))) { 263 return !printf("%.9f %.9f ", (double)x, (double)y); 264 } 265 } 266 printf("%.9f %.9f ", (double)(sx + lx), (double)(sy + ly)); 267 return 0; 268 }