LightOJ 1285 Drawing Simple Polygon (Convex Hull && Simulation)

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 */
View Code

整理后的代码:

  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 }
View Code

——written by Lyon

原文地址:https://www.cnblogs.com/LyonLys/p/LOJ_1285_Lyon.html