Jan's LightOJ :: Problem 1285 - Drawing Simple Polygon
搞了挺久的一道题,通过率挺低的。
题意是,给出一堆点,要求求出一个多边形,多边形上每一条边不与其他的边相交,而且多边形要用给出的所有点。如果能构成多边形,就输出多边形的点的序号,否则就输出"Impossible"。
做法是,对所有的点做凸包,每次做出凸包后对剩余的点继续做凸包,直到的到很多个一层包含一层的凸包。然后剩下的操作就是模拟相邻两层间的连结了。
对于我代码中注释的第一组数据:
对所有的点做凸包后:
然后模拟遍历各个凸包的做法:
其实很容易可以发现,对于每一个凸包跟相邻的凸包连接的时候,可以挑选任意的一条边跟另一个凸包相连,因为这条边总可以在相邻的凸包上找到这样的一个满足不会相交的要求的位置。所以,对于每一个凸包,我们只需要递归找到下一个凸包进入位置就可以了。
带debug的代码如下:
1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 #include <cstring> 5 #include <vector> 6 #include <ctime> 7 #include <cmath> 8 #include <set> 9 10 using namespace std; 11 12 typedef long long LL; 13 14 struct Point { 15 LL x, y; 16 int id; 17 Point() {} 18 Point(LL x, LL y) : x(x), y(y) {} 19 } ; 20 21 bool operator < (Point x, Point y) { return x.x < y.x || (x.x == y.x && x.y < y.y);} 22 bool operator == (Point x, Point y) { return x.x == y.x && x.y == y.y;} 23 Point operator - (Point x, Point y) { return Point(x.x - y.x, x.y - y.y);} 24 25 inline LL dotDet(Point x, Point y) { return x.x * y.x + x.y * y.y;} 26 inline LL crossDet(Point x, Point y) { return x.x * y.y - x.y * y.x;} 27 inline LL crossDet(Point o, Point a, Point b) { return crossDet(a - o, b - o);} 28 29 const int N = 2222; 30 bool vis[N]; 31 Point pt[N]; 32 vector<Point> ch[N]; 33 34 bool check(Point *pt, int n) { 35 for (int i = 2; i < n; i++) { 36 if (crossDet(pt[0], pt[1], pt[i])) return false; 37 } 38 return true; 39 } 40 41 void andrew(Point *pt, int n, vector<Point> &ch) { 42 sort(pt, pt + n); 43 ch.clear(); 44 int sz; 45 if (check(pt, n)) { 46 for (int i = 0; i < n; i++) ch.push_back(pt[i]); 47 sz = ch.size(); 48 for (int i = 0; i < sz; i++) { 49 vis[ch[i].id] = true; 50 } 51 return ; 52 } 53 for (int i = 0; i < n; i++) { 54 while ((sz = ch.size()) > 1 && crossDet(ch[sz - 2], ch[sz - 1], pt[i]) < 0) ch.pop_back(); 55 ch.push_back(pt[i]); 56 } 57 int mk = ch.size(); 58 for (int i = n - 2; i >= 0; i--) { 59 while ((sz = ch.size()) > mk && crossDet(ch[sz - 2], ch[sz - 1], pt[i]) < 0) ch.pop_back(); 60 ch.push_back(pt[i]); 61 } 62 // cout << ch.size() << endl; 63 if (n > 1) ch.pop_back(); 64 sz = ch.size(); 65 for (int i = 0; i < sz; i++) { 66 vis[ch[i].id] = true; 67 } 68 } 69 70 inline bool onSeg(Point x, Point a, Point b) { return crossDet(a - x, b - x) == 0 && dotDet(a - x, b - x) < 0;} 71 72 int segIntersect(Point a, Point c, Point b, Point d) { 73 Point v1 = b - a, v2 = c - b, v3 = d - c, v4 = a - d; 74 LL a_bc = crossDet(v1, v2); 75 LL b_cd = crossDet(v2, v3); 76 LL c_da = crossDet(v3, v4); 77 LL d_ab = crossDet(v4, v1); 78 if (a_bc * c_da > 0 && b_cd * d_ab > 0) return 1; 79 if (onSeg(b, a, c)) return 2; 80 if (onSeg(c, b, d)) return 2; 81 if (onSeg(d, c, a)) return 2; 82 if (onSeg(a, d, b)) return 2; 83 // if (onSeg(b, a, c) && c_da) return 2; 84 // if (onSeg(c, b, d) && d_ab) return 2; 85 // if (onSeg(d, c, a) && a_bc) return 2; 86 // if (onSeg(a, d, b) && b_cd) return 2; 87 return 0; 88 } 89 90 int path[N], pc; 91 92 bool check(int id, int a, int b, int c, int d) { 93 Point pa = ch[id][a], pb = ch[id][b], pc = ch[id - 1][c], pd = ch[id - 1][d]; 94 if (segIntersect(pa, pc, pb, pd)) return false; 95 for (int i = 0, sz = ch[id].size(); i < sz; i++) { 96 // cout << ch[id][i].x << ' ' << ch[id][i].y << ' ' << pa.x << ' ' << pa.y << ' ' << pc.x << ' ' << pc.y << endl; 97 int res1 = segIntersect(ch[id][i], ch[id][(i + 1) % sz], pa, pc); 98 int res2 = segIntersect(ch[id][i], ch[id][(i + 1) % sz], pb, pd); 99 // cout << res1 << " = = " << res2 << endl; 100 if (res1 == 1 || res2 == 1) return false; 101 if (res1 == 2 && !(pa == ch[id][i]) && !(pa == ch[id][(i + 1) % sz])) return false; 102 if (res2 == 2 && !(pb == ch[id][i]) && !(pb == ch[id][(i + 1) % sz])) return false; 103 } 104 return true; 105 } 106 107 void dfs(int cur, int cnt, int mk) { 108 if (cur > cnt - 1) return ; 109 if (ch[cur].size() == 1) { 110 path[pc++] = ch[cur][0].id; 111 return ; 112 } 113 if (ch[cur].size() == 2) { 114 int p1 = mk, p2 = (mk + 1) % ch[cur - 1].size(); 115 Point a = ch[cur][0], b = ch[cur][1], c = ch[cur - 1][p1], d = ch[cur - 1][p2]; 116 if (!segIntersect(a, c, b, d) ^ ((cur & 1) != 0)) { 117 path[pc++] = b.id; 118 path[pc++] = a.id; 119 } else { 120 path[pc++] = a.id; 121 path[pc++] = b.id; 122 } 123 return ; 124 } 125 int bg = 0; 126 if (cur) { 127 int p1 = mk, p2 = (mk + 1) % ch[cur - 1].size(), np1 = 0, np2 = 1; 128 while (true) { 129 if (check(cur, np1, np2, p1, p2)) break; 130 np1++, np2++; 131 if (np1 >= ch[cur].size()) { 132 np1 = 0, np2 = 1; 133 reverse(ch[cur].begin(), ch[cur].end()); 134 continue; 135 } 136 np1 %= ch[cur].size(), np2 %= ch[cur].size(); 137 } 138 // cout << ch[cur - 1][p1].id << ' ' << ch[cur - 1][p2].id << ' ' << ch[cur][np1].id << ' ' << ch[cur][np2].id << endl; 139 if (cur & 1) mk = np1; 140 else mk = np2; 141 path[pc++] = ch[cur][mk].id; 142 bg++; 143 if (cur & 1) { 144 dfs(cur + 1, cnt, (np1 + ch[cur].size() - 1) % ch[cur].size()); 145 } else { 146 dfs(cur + 1, cnt, (np1 + 1) % ch[cur].size()); 147 } 148 } 149 if (cur & 1) { 150 for (int i = bg, t, sz = ch[cur].size(); i < sz; i++) { 151 t = (mk + sz - i) % sz; 152 path[pc++] = ch[cur][t].id; 153 } 154 } else { 155 for (int i = bg, t, sz = ch[cur].size(); i < sz; i++) { 156 t = (i + mk) % sz; 157 path[pc++] = ch[cur][t].id; 158 } 159 } 160 if (!cur) dfs(cur + 1, cnt, ch[cur].size() - 1); 161 } 162 163 Point backUp[N]; 164 165 bool checkAns(int n) { 166 for (int i = 0; i < n; i++) { 167 for (int j = i + 2; j < n; j++) { 168 if (segIntersect(backUp[path[i]], backUp[path[(i + 1) % n]], backUp[path[j]], backUp[path[(j + 1) % n]]) == 1) return false; 169 } 170 } 171 return true; 172 } 173 174 #define RUN 1 175 176 int main() { 177 int T, n; 178 #if RUN 179 // freopen("in", "r", stdin); 180 cin >> T; 181 for (int cas = 1; cas <= T; cas++) { 182 cin >> n; 183 for (int i = 0; i < n; i++) { 184 cin >> pt[i].x >> pt[i].y; 185 pt[i].id = i; 186 vis[i] = false; 187 backUp[i] = pt[i]; 188 } 189 cout << "Case " << cas << ":" << endl; 190 #else 191 freopen("in", "w", stdout); 192 while (true) { 193 n = 20; 194 srand(time(0)); 195 for (int i = 0; i < n; i++) { 196 Point tmp; 197 tmp.x = rand() % 100, tmp.y = rand() % 100; 198 for (int j = 0; j < i; j++) { 199 if (tmp == pt[j]) { 200 i--; 201 tmp = pt[i]; 202 break; 203 } 204 } 205 tmp.id = i; 206 vis[i] = false; 207 pt[i] = backUp[i] = tmp; 208 } 209 #endif 210 int cnt = 0; 211 if (check(pt, n)) { 212 puts("Impossible"); 213 continue; 214 } 215 int t = n; 216 while (n) { 217 andrew(pt, n, ch[cnt]); 218 // cout << "sz~~~ " << ch[cnt].size() << endl; 219 // for (int i = 0; i < ch[cnt].size(); i++) cout << ch[cnt][i].id << ' '; cout << endl; 220 cnt++; 221 int m = 0; 222 for (int i = 0; i < n; i++) { 223 if (!vis[pt[i].id]) { 224 pt[m++] = pt[i]; 225 } 226 } 227 n = m; 228 } 229 // cout << "cnt " << cnt << endl; 230 pc = 0; 231 dfs(0, cnt, 0); 232 if (pc != t) { 233 cout << "Lacking sth." << endl; 234 #if !RUN 235 cout << t << ' ' << pc << endl; 236 for (int i = 0; i < t; i++) cout << backUp[i].x << ' ' << backUp[i].y << endl; 237 return 1; 238 #endif 239 while (1) ; 240 } 241 if (!checkAns(t)) { 242 cout << "Bug!!!" << endl; 243 for (int i = 0; i < pc; i++) { 244 if (i) putchar(' '); 245 cout << path[i]; 246 } 247 cout << endl; 248 #if !RUN 249 cout << t << endl; 250 for (int i = 0; i < t; i++) cout << backUp[i].x << ' ' << backUp[i].y << endl; 251 return 1; 252 #endif 253 while (1) ; 254 } 255 #if RUN 256 for (int i = 0; i < pc; i++) { 257 if (i) putchar(' '); 258 cout << path[i]; 259 } 260 cout << endl; 261 #endif 262 } 263 return 0; 264 } 265 266 /* 267 13 268 20 269 75 62 270 43 70 271 72 58 272 97 14 273 9 92 274 44 99 275 31 52 276 43 19 277 22 94 278 84 51 279 20 85 280 89 69 281 41 58 282 38 62 283 32 19 284 1 1 285 61 49 286 3 56 287 17 19 288 42 96 289 25 290 44 26 291 48 65 292 35 64 293 64 71 294 84 34 295 38 70 296 11 89 297 46 99 298 42 5 299 88 2 300 32 33 301 46 34 302 27 76 303 61 71 304 29 25 305 89 13 306 79 51 307 9 40 308 93 87 309 11 10 310 86 82 311 7 17 312 67 9 313 46 26 314 30 48 315 10 316 0 0 317 1 1 318 2 2 319 3 3 320 0 3 321 3 0 322 -10 -10 323 10 -10 324 10 10 325 -10 10 326 6 327 0 0 328 1 1 329 2 2 330 3 3 331 0 3 332 3 0 333 9 334 1 2 335 2 1 336 4 1 337 4 3 338 6 2 339 6 4 340 4 5 341 1 5 342 2 3 343 4 344 0 0 345 2 2 346 1 1 347 3 3 348 16 349 -10000 -10000 350 -10000 10000 351 10000 -10000 352 10000 10000 353 0 -1000 354 0 1000 355 -1000 0 356 1000 0 357 -100 -100 358 -100 100 359 100 -100 360 100 100 361 0 -10 362 0 10 363 -10 0 364 10 0 365 366 4 367 0 0 368 2 0 369 0 1 370 1 0 371 6 372 1 0 373 2 0 374 3 0 375 1 1 376 2 1 377 3 1 378 5 379 0 0 380 10 0 381 10 5 382 5 -1 383 0 5 384 9 385 0 500 386 -500 0 387 500 0 388 250 249 389 -250 249 390 0 1 391 10 100 392 -10 100 393 0 110 394 6 395 0 1 396 0 2 397 0 3 398 -250 0 399 250 0 400 0 500 401 6 402 -249 1 403 -248 2 404 -247 3 405 -250 0 406 250 0 407 0 500 408 */
整理后的代码:
1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 #include <cstring> 5 #include <vector> 6 #include <ctime> 7 #include <cmath> 8 #include <set> 9 10 using namespace std; 11 12 typedef long long LL; 13 14 struct Point { 15 LL x, y; 16 int id; 17 Point() {} 18 Point(LL x, LL y) : x(x), y(y) {} 19 } ; 20 21 bool operator < (Point x, Point y) { return x.x < y.x || (x.x == y.x && x.y < y.y);} 22 bool operator == (Point x, Point y) { return x.x == y.x && x.y == y.y;} 23 Point operator - (Point x, Point y) { return Point(x.x - y.x, x.y - y.y);} 24 25 inline LL dotDet(Point x, Point y) { return x.x * y.x + x.y * y.y;} 26 inline LL crossDet(Point x, Point y) { return x.x * y.y - x.y * y.x;} 27 inline LL crossDet(Point o, Point a, Point b) { return crossDet(a - o, b - o);} 28 29 const int N = 2222; 30 bool vis[N]; 31 Point pt[N]; 32 vector<Point> ch[N]; 33 34 bool check(Point *pt, int n) { 35 for (int i = 2; i < n; i++) { 36 if (crossDet(pt[0], pt[1], pt[i])) return false; 37 } 38 return true; 39 } 40 41 void andrew(Point *pt, int n, vector<Point> &ch) { 42 sort(pt, pt + n); 43 ch.clear(); 44 int sz; 45 if (check(pt, n)) { 46 for (int i = 0; i < n; i++) ch.push_back(pt[i]); 47 sz = ch.size(); 48 for (int i = 0; i < sz; i++) { 49 vis[ch[i].id] = true; 50 } 51 return ; 52 } 53 for (int i = 0; i < n; i++) { 54 while ((sz = ch.size()) > 1 && crossDet(ch[sz - 2], ch[sz - 1], pt[i]) < 0) ch.pop_back(); 55 ch.push_back(pt[i]); 56 } 57 int mk = ch.size(); 58 for (int i = n - 2; i >= 0; i--) { 59 while ((sz = ch.size()) > mk && crossDet(ch[sz - 2], ch[sz - 1], pt[i]) < 0) ch.pop_back(); 60 ch.push_back(pt[i]); 61 } 62 if (n > 1) ch.pop_back(); 63 sz = ch.size(); 64 for (int i = 0; i < sz; i++) { 65 vis[ch[i].id] = true; 66 } 67 } 68 69 inline bool onSeg(Point x, Point a, Point b) { return crossDet(a - x, b - x) == 0 && dotDet(a - x, b - x) < 0;} 70 71 int segIntersect(Point a, Point c, Point b, Point d) { 72 Point v1 = b - a, v2 = c - b, v3 = d - c, v4 = a - d; 73 LL a_bc = crossDet(v1, v2); 74 LL b_cd = crossDet(v2, v3); 75 LL c_da = crossDet(v3, v4); 76 LL d_ab = crossDet(v4, v1); 77 if (a_bc * c_da > 0 && b_cd * d_ab > 0) return 1; 78 if (onSeg(b, a, c)) return 2; 79 if (onSeg(c, b, d)) return 2; 80 if (onSeg(d, c, a)) return 2; 81 if (onSeg(a, d, b)) return 2; 82 return 0; 83 } 84 85 int path[N], pc; 86 87 bool check(int id, int a, int b, int c, int d) { 88 Point pa = ch[id][a], pb = ch[id][b], pc = ch[id - 1][c], pd = ch[id - 1][d]; 89 if (segIntersect(pa, pc, pb, pd)) return false; 90 for (int i = 0, sz = ch[id].size(); i < sz; i++) { 91 int res1 = segIntersect(ch[id][i], ch[id][(i + 1) % sz], pa, pc); 92 int res2 = segIntersect(ch[id][i], ch[id][(i + 1) % sz], pb, pd); 93 if (res1 == 1 || res2 == 1) return false; 94 if (res1 == 2 && !(pa == ch[id][i]) && !(pa == ch[id][(i + 1) % sz])) return false; 95 if (res2 == 2 && !(pb == ch[id][i]) && !(pb == ch[id][(i + 1) % sz])) return false; 96 } 97 return true; 98 } 99 100 void dfs(int cur, int cnt, int mk) { 101 if (cur > cnt - 1) return ; 102 if (ch[cur].size() == 1) { 103 path[pc++] = ch[cur][0].id; 104 return ; 105 } 106 if (ch[cur].size() == 2) { 107 int p1 = mk, p2 = (mk + 1) % ch[cur - 1].size(); 108 Point a = ch[cur][0], b = ch[cur][1], c = ch[cur - 1][p1], d = ch[cur - 1][p2]; 109 if (!segIntersect(a, c, b, d) ^ ((cur & 1) != 0)) { 110 path[pc++] = b.id; 111 path[pc++] = a.id; 112 } else { 113 path[pc++] = a.id; 114 path[pc++] = b.id; 115 } 116 return ; 117 } 118 int bg = 0; 119 if (cur) { 120 int p1 = mk, p2 = (mk + 1) % ch[cur - 1].size(), np1 = 0, np2 = 1; 121 while (true) { 122 if (check(cur, np1, np2, p1, p2)) break; 123 np1++, np2++; 124 if (np1 >= ch[cur].size()) { 125 np1 = 0, np2 = 1; 126 reverse(ch[cur].begin(), ch[cur].end()); 127 continue; 128 } 129 np1 %= ch[cur].size(), np2 %= ch[cur].size(); 130 } 131 if (cur & 1) mk = np1; 132 else mk = np2; 133 path[pc++] = ch[cur][mk].id; 134 bg++; 135 if (cur & 1) { 136 dfs(cur + 1, cnt, (np1 + ch[cur].size() - 1) % ch[cur].size()); 137 } else { 138 dfs(cur + 1, cnt, (np1 + 1) % ch[cur].size()); 139 } 140 } 141 if (cur & 1) { 142 for (int i = bg, t, sz = ch[cur].size(); i < sz; i++) { 143 t = (mk + sz - i) % sz; 144 path[pc++] = ch[cur][t].id; 145 } 146 } else { 147 for (int i = bg, t, sz = ch[cur].size(); i < sz; i++) { 148 t = (i + mk) % sz; 149 path[pc++] = ch[cur][t].id; 150 } 151 } 152 if (!cur) dfs(cur + 1, cnt, ch[cur].size() - 1); 153 } 154 155 Point backUp[N]; 156 157 bool checkAns(int n) { 158 for (int i = 0; i < n; i++) { 159 for (int j = i + 2; j < n; j++) { 160 if (segIntersect(backUp[path[i]], backUp[path[(i + 1) % n]], backUp[path[j]], backUp[path[(j + 1) % n]]) == 1) return false; 161 } 162 } 163 return true; 164 } 165 166 int main() { 167 int T, n; 168 // freopen("in", "r", stdin); 169 scanf("%d", &T); 170 for (int cas = 1; cas <= T; cas++) { 171 scanf("%d", &n); 172 for (int i = 0; i < n; i++) { 173 scanf("%lld%lld", &pt[i].x, &pt[i].y); 174 pt[i].id = i; 175 vis[i] = false; 176 backUp[i] = pt[i]; 177 } 178 printf("Case %d:\n", cas); 179 int cnt = 0; 180 if (check(pt, n)) { 181 puts("Impossible"); 182 continue; 183 } 184 int t = n; 185 while (n) { 186 andrew(pt, n, ch[cnt]); 187 cnt++; 188 int m = 0; 189 for (int i = 0; i < n; i++) { 190 if (!vis[pt[i].id]) { 191 pt[m++] = pt[i]; 192 } 193 } 194 n = m; 195 } 196 pc = 0; 197 dfs(0, cnt, 0); 198 for (int i = 0; i < pc; i++) { 199 if (i) putchar(' '); 200 printf("%d", path[i]); 201 } 202 puts(""); 203 } 204 return 0; 205 }
——written by Lyon