zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    Linux查看系统信息
    pgrep 和 pkill 使用小记
    linux下json库的编译及例程
    Epoll 实例
    gcc中的内嵌汇编语言
    BZOJ 1053: [HAOI2007]反素数ant
    2018.7.15模拟赛
    BZOJ 2002: [Hnoi2010]Bounce 弹飞绵羊
    BZOJ 4241: 历史研究
    LUOGU P2365 任务安排
  • 原文地址:https://www.cnblogs.com/LyonLys/p/LOJ_1285_Lyon.html
Copyright © 2011-2022 走看看