HIT Summer Day17 计算几何初步 题解

ABC题意及解法见课件。这里附上代码。

A:POJ 2318

 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 <iomanip>
16 #include <cctype>
17 #include <cassert>
18 #include <bitset>
19 #include <ctime>
20 
21 using namespace std;
22 
23 #define pau system("pause")
24 #define ll long long
25 #define pii pair<int, int>
26 #define pb push_back
27 #define mp make_pair
28 #define clr(a, x) memset(a, x, sizeof(a))
29 
30 const double pi = acos(-1.0);
31 const int INF = 0x3f3f3f3f;
32 const int MOD = 1e9 + 7;
33 const double EPS = 1e-9;
34 
35 struct point {
36     int x, y;
37     point () {}
38     point (int x, int y) : x(x), y(y) {}
39     void input() {
40         scanf("%d%d", &x, &y);
41     }
42 };
43 struct segment {
44     point p1, p2;
45     segment () {}
46     segment (point p1, point p2) : p1(p1), p2(p2) {}
47     void input() {
48         p1.input();
49         p2.input();
50     }
51 } seg[5015];
52 double cross_mul(point p1, point p2, point p3) {
53     return (p2.x - p1.x) * (p3.y - p1.y) - (p3.x - p1.x) * (p2.y - p1.y);
54 }
55 bool ok(segment s, point p) {
56     return cross_mul(s.p1, s.p2, p) < 0;
57 }
58 int n, m, x_left, x_right, y_up, y_down, is_first = 1, cnt[5015];
59 int main() {
60     while (~scanf("%d", &n) && n) {
61         scanf("%d%d%d%d%d", &m, &x_left, &y_up, &x_right, &y_down);
62         seg[0] = segment(point(x_left, y_down), point(x_left, y_up));
63         for (int i = 1; i <= n; ++i) {
64             int u, l;
65             scanf("%d%d", &u, &l);
66             seg[i] = segment(point(l, y_down), point(u, y_up));
67         }
68         clr(cnt, 0);
69         for (int i = 1; i <= m; ++i) {
70             int x, y;
71             scanf("%d%d", &x, &y);
72             int l = 0, r = n, mi, res;
73             while (l <= r) {
74                 mi = l + r >> 1;
75                 if (ok(seg[mi], point(x, y))) {
76                     l = (res = mi) + 1;
77                 } else {
78                     r = mi - 1;
79                 }
80             }
81             ++cnt[res];
82         }
83         if (is_first) {
84             is_first = 0;
85         } else {
86             puts("");
87         }
88         for (int i = 0; i <= n; ++i) {
89             printf("%d: %d
", i, cnt[i]);
90         }
91     }
92     return 0;
93 }
View Code

B: POJ 3304

 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 <iomanip>
16 #include <cctype>
17 #include <cassert>
18 #include <bitset>
19 #include <ctime>
20 
21 using namespace std;
22 
23 #define pau system("pause")
24 #define ll long long
25 #define pii pair<int, int>
26 #define pb push_back
27 #define mp make_pair
28 #define clr(a, x) memset(a, x, sizeof(a))
29 
30 const double pi = acos(-1.0);
31 const int INF = 0x3f3f3f3f;
32 const int MOD = 1e9 + 7;
33 const double EPS = 1e-8;
34 
35 int T, n;
36 struct point {
37     double x, y;
38     point () {}
39     point (double x, double y) : x(x), y(y) {}
40     void input() {
41         scanf("%lf%lf", &x, &y);
42     }
43     double dis(point p) {
44         return sqrt((x - p.x) * (x - p.x) + (y - p.y) * (y - p.y));
45     }
46 };
47 struct seg {
48     point p1, p2;
49     seg () {}
50     seg (point p1, point p2) : p1(p1), p2(p2) {}
51     void input() {
52         p1.input();
53         p2.input();
54     }
55 } s[105];
56 double cross_mul(point p1, point p2, point p3) {
57     return (p2.x - p1.x) * (p3.y - p1.y) - (p3.x - p1.x) * (p2.y - p1.y);
58 }
59 bool cross(point pa, point pb, seg l) {
60     point p1 = l.p1, p2 = l.p2;
61     return cross_mul(pa, pb, p1) * cross_mul(pa, pb, p2) <= EPS;
62 }
63 bool solve(point p1, point p2) {
64     if (p1.dis(p2) <= EPS) return false;
65     for (int i = 1; i <= n; ++i) {
66         if (!cross(p1, p2, s[i])) {
67             return false;
68         }
69     }
70     return true;
71 }
72 int main() {
73     scanf("%d", &T);
74     while (T--) {
75         scanf("%d", &n);
76         for (int i = 1; i <= n; ++i) {
77             s[i].input();
78         }
79         bool ans = 0;
80         if (1 == n) ans = 1;
81         for (int i = 1; i < n; ++i) {
82             point p1 = s[i].p1, p2 = s[i].p2;
83             for (int j = i + 1; j <= n; ++j) {
84                 point p3 = s[j].p1, p4 = s[j].p2;
85                 if (solve(p1, p3) || solve(p1, p4) || solve(p2, p3) || solve(p2, p4)) {
86                     ans = 1;
87                 }
88             }
89         }
90         puts(ans ? "Yes!" : "No!");
91     }
92     return 0;
93 }
View Code

C: POJ 1127

  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 <iomanip>
 16 #include <cctype>
 17 #include <cassert>
 18 #include <bitset>
 19 #include <ctime>
 20 
 21 using namespace std;
 22 
 23 #define pau system("pause")
 24 #define ll long long
 25 #define pii pair<int, int>
 26 #define pb push_back
 27 #define mp make_pair
 28 #define clr(a, x) memset(a, x, sizeof(a))
 29 
 30 const double pi = acos(-1.0);
 31 const int INF = 0x3f3f3f3f;
 32 const int MOD = 1e9 + 7;
 33 const double EPS = 1e-6;
 34 
 35 struct point {
 36     int x, y;
 37     point () {}
 38     point (int x, int y) : x(x), y(y) {}
 39     point operator - (const point &p) const {
 40         return point(x - p.x, y - p.y);}
 41 };
 42 struct seg {
 43     point p1, p2;
 44     seg () {}
 45     seg (point p1, point p2) : p1(p1), p2(p2) {}
 46 };
 47 int cross_mul(point p1, point p2) {
 48     return p1.x * p2.y - p1.y * p2.x;
 49 }
 50 bool between(point a, point b, point c) {// a between b and c
 51     return (a.x - b.x) * (a.x - c.x) <= 0 && (a.y - b.y) * (a.y - c.y) <= 0;
 52 }
 53 bool cross(seg l1, seg l2) {
 54     int res1 = cross_mul(l1.p2 - l1.p1, l2.p1 - l1.p1);
 55     int res2 = cross_mul(l1.p2 - l1.p1, l2.p2 - l1.p1);
 56     int res3 = cross_mul(l2.p2 - l2.p1, l1.p1 - l2.p1);
 57     int res4 = cross_mul(l2.p2 - l2.p1, l1.p2 - l2.p1);
 58     if (!(res1 | res2 | res3 | res4)) {
 59         return between(l1.p1, l2.p1, l2.p2) || between(l1.p2, l2.p1, l2.p2) || 
 60                between(l2.p1, l1.p1, l1.p2) || between(l2.p2, l1.p1, l1.p2);
 61     }
 62     return res1 * res2 <= 0 && res3 * res4 <= 0;
 63 }
 64 int Rank[15], parent[15], n;
 65 void ini() {
 66     for (int i = 1; i <= n; ++i) {
 67         Rank[i] = 1;
 68         parent[i] = i;
 69     }
 70 }
 71 int Find(int x) {return x == parent[x] ? x : parent[x] = Find(parent[x]);}
 72 void uni(int x, int y) {
 73     x = Find(x), y = Find(y);
 74     if (x == y) return;
 75 
 76     if (Rank[x] < Rank[y]) {
 77         parent[x] = y;
 78     } else {
 79         parent[y] = x;
 80         if (Rank[x] == Rank[y]) ++Rank[x];
 81     }
 82 }
 83 seg s[15];
 84 int main() {
 85     while (~scanf("%d", &n) && n) {
 86         for (int i = 1; i <= n; ++i) {
 87             scanf("%d%d%d%d", &s[i].p1.x, &s[i].p1.y, &s[i].p2.x, &s[i].p2.y);
 88         }
 89         ini();
 90         for (int i = 1; i <= n; ++i) {
 91             for (int j = i + 1; j <= n; ++j) {
 92                 if (cross(s[i], s[j])) uni(i, j);
 93             }
 94         }
 95         int x, y;
 96         while (~scanf("%d%d", &x, &y) && x && y) {
 97             puts(Find(x) == Find(y) ? "CONNECTED" : "NOT CONNECTED");
 98         }
 99     }
100     return 0;
101 }
View Code

D: POJ 1696

题意:

一只蚂蚁只能向左走或直走,且不能经过之前走过的路径,问路径最多能覆盖多少个点。

思路:

每次选择蚂蚁左边未走过的最靠右的点。实际上,未走过的点永远在蚂蚁的左边;且蚂蚁的路径不会和之前有交点。这两条性质都可以类数学归纳法证明。这样便会遍历到所有的点。

因此,每次贪心选以上一个位置为极点,极角最小的点。

  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 mp make_pair
 29 #define clr(a, x) memset(a, x, sizeof(a))
 30 
 31 const double pi = acos(-1.0);
 32 const int INF = 0x3f3f3f3f;
 33 const int MOD = 1e9 + 7;
 34 const double EPS = 1e-9;
 35 
 36 /*
 37 #include <ext/pb_ds/assoc_container.hpp>
 38 #include <ext/pb_ds/tree_policy.hpp>
 39 
 40 using namespace __gnu_pbds;
 41 tree<pli, null_type, greater<pli>, rb_tree_tag, tree_order_statistics_node_update> T;
 42 */
 43 
 44 struct Point {
 45     int x, y;
 46     Point () {}
 47     Point (int x, int y) : x(x), y(y) {}
 48     ll operator ^ (const Point &p) const {
 49         return x * p.y - y * p.x;
 50     }
 51     Point operator - (const Point &p) const {
 52         return Point(x - p.x, y - p.y);
 53     }
 54     bool operator == (const Point &p) const {
 55         return x == p.x && y == p.y;
 56     }
 57     bool operator < (const Point &p) const {
 58         return y == p.y ? x < p.x : y < p.y;
 59     }
 60     void input() {
 61         scanf("%d", &x);
 62         scanf("%d%d", &x, &y);
 63     }
 64     void output() {
 65         printf("%d %d
", x, y);
 66     }
 67     double dis(const Point &p) const {
 68         return sqrt((x - p.x) * (x - p.x) + (y - p.y) * (y - p.y));
 69     }
 70 } p[1015], pp;
 71 bool cmp(const Point &p1, const Point &p2) {
 72     ll v = (p1 - pp) ^ (p2 - pp);
 73     if (v) return v > 0;
 74     return abs(p1.x - pp.x) + abs(p1.y - pp.y) < abs(p2.x - pp.x) + abs(p2.y - pp.y);
 75 }
 76 int cross(Point pp, Point p1, Point p2) {
 77     return ((p1 - pp) ^ (p2 - pp)) > 0;
 78 }
 79 int T, n, vis[55];
 80 vector<int> vec;
 81 int main() {
 82     scanf("%d", &T);
 83     while (T--) {
 84         scanf("%d", &n);
 85         for (int i = 1; i <= n; ++i) {
 86             p[i].input();
 87             vis[i] = 0;
 88         }
 89         pp = p[1]; int id = 1;
 90         for (int i = 2; i <= n; ++i) {
 91             if (p[i] < pp) {
 92                 pp = p[i];
 93                 id = i;
 94             }
 95         }
 96         vec.clear();
 97         vis[id] = 1; vec.pb(id);
 98         for (int i = 1; i < n; ++i) {
 99             int j = 1;
100             for (; j <= n; ++j) {
101                 if (!vis[j]) {
102                     id = j;
103                     break;
104                 }
105             }
106             for (++j; j <= n; ++j) {
107                 if (vis[j]) continue;
108                 if (cmp(p[j], p[id])) {
109                     id = j;
110                 }
111             }
112             vis[id] = 1; vec.pb(id);
113             pp = p[id];
114         }
115         printf("%d", n);
116         for (int i = 0; i < vec.size(); ++i) {
117             printf(" %d", vec[i]);
118         }
119         puts("");
120     }
121     return 0;
122 }
View Code

E: HDU 1705

题意:对一个整点三角形,问内部有多少整点。

思路:求出面积S,对于边(x1, y1), (x2, y2),其上的整点数为gcd(abs(x1 - x2), abs(y1 - y2))。如此累计便得出边上整点数s。 n = S - s / 2 + 1.

 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 mp make_pair
29 #define clr(a, x) memset(a, x, sizeof(a))
30 
31 const double pi = acos(-1.0);
32 const int INF = 0x3f3f3f3f;
33 const int MOD = 1e9 + 7;
34 const double EPS = 1e-9;
35 
36 /*
37 #include <ext/pb_ds/assoc_container.hpp>
38 #include <ext/pb_ds/tree_policy.hpp>
39 
40 using namespace __gnu_pbds;
41 tree<pli, null_type, greater<pli>, rb_tree_tag, tree_order_statistics_node_update> T;
42 */
43 
44 int x[3], y[3];
45 int main() {
46     while (1) {
47         int flag = 0;
48         for (int i = 0; i < 3; ++i) {
49             scanf("%d%d", &x[i], &y[i]);
50             if (x[i] || y[i]) flag = 1;
51         }
52         if (!flag) break;
53         int S = abs((x[1] - x[0]) * (y[2] - y[0]) - (x[2] - x[0]) * (y[1] - y[0])) / 2;
54         ll s = 0;
55         for (int i = 0; i < 3; ++i) {
56             s += __gcd(abs(x[(i + 1) % 3] - x[i]), abs(y[(i + 1) % 3] - y[i]));
57         }
58         printf("%d
", S + 1 - s / 2);
59     }
60     return 0;
61 }
View Code

F: HDU 1756

题意: 判断一个点是否在多边形内部。

思路:先判断是否在边上。再点射法求出水平射线与下降端点和边的相交次数和。为奇数在内部,为偶数在外部。

  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 mp make_pair
 29 #define clr(a, x) memset(a, x, sizeof(a))
 30 
 31 const double pi = acos(-1.0);
 32 const int INF = 0x3f3f3f3f;
 33 const int MOD = 1e9 + 7;
 34 const double EPS = 1e-9;
 35 
 36 /*
 37 #include <ext/pb_ds/assoc_container.hpp>
 38 #include <ext/pb_ds/tree_policy.hpp>
 39 
 40 using namespace __gnu_pbds;
 41 tree<pli, null_type, greater<pli>, rb_tree_tag, tree_order_statistics_node_update> T;
 42 */
 43 
 44 int n, m;
 45 struct Point {
 46     int x, y, cnt_down;
 47     Point () {}
 48     Point (int _x, int _y) {
 49         x = _x, y = _y, cnt_down = 0;
 50     }
 51     Point operator - (const Point &p) const {
 52         return Point(x - p.x, y - p.y);
 53     }
 54     ll operator ^ (const Point &p) const {
 55         return x * p.y - y * p.x;
 56     }
 57     void input() {
 58         scanf("%d%d", &x, &y);
 59         cnt_down = 0;
 60     }
 61 } p[105];
 62 struct Seg {
 63     Point s, e;
 64     Seg () {}
 65     Seg (Point s, Point e) : s(s), e(e) {}
 66     bool cross(const Seg &seg) const {
 67         return ((s - seg.s) ^ (seg.e - seg.s)) * ((e - seg.s) ^ (seg.e - seg.s)) < 0;
 68     }
 69 };
 70 bool between(Point p, Seg seg) {
 71     if ((p - seg.s) ^ (seg.e - seg.s)) return false;
 72     return (p.x - seg.s.x) * (p.x - seg.e.x) <= 0 && (p.y - seg.s.y) * (p.y - seg.e.y) <= 0;
 73 }
 74 int main() {
 75     while (~scanf("%d", &n)) {
 76         for (int i = 1; i <= n; ++i) {
 77             p[i].input();
 78         }
 79         for (int i = 1; i <= n; ++i) {
 80             int j = i % n + 1;
 81             if (p[i].y < p[j].y) ++p[i].cnt_down;
 82             else if (p[j].y < p[i].y) ++p[j].cnt_down;
 83         }
 84         scanf("%d", &m);
 85         while (m--) {
 86             Point pp; pp.input();
 87             int f = 0;
 88             for (int i = 1; i <= n; ++i) {
 89                 if (between(pp, Seg(p[i], p[i % n + 1]))) {
 90                     f = 1;
 91                     break;
 92                 }
 93             }
 94             if (f) {
 95                 puts("Yes");
 96                 continue;
 97             }
 98             Seg ss = Seg(pp, Point(1001, pp.y));
 99             int cnt = 0;
100             for (int i = 1; i <= n; ++i) {
101                 if (between(p[i], ss)) cnt += p[i].cnt_down;
102             }
103             for (int i = 1; i <= n; ++i) {
104                 if (ss.cross(Seg(p[i], p[i % n + 1])) && Seg(p[i], p[i % n + 1]).cross(ss)) ++cnt;
105             }
106             puts(cnt & 1 ? "Yes" : "No");
107         }
108     }
109     return 0;
110 }
View Code

G: POJ 1556

题意:矩形内n组墙,每组墙由中间两块空隙构成。问从起点到终点不撞墙的最短距离。

思路:最短路径的所有线段端点一定都是原来墙的端点。于是对于第i组墙的第j个点,枚举所有转移到他上的端点,判断两点连线是否撞墙。如不撞墙,更新dp值。最终dp[n + 1][1]即为所求。

复杂度O(n^3).

  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 mp make_pair
 29 #define clr(a, x) memset(a, x, sizeof(a))
 30 
 31 const double pi = acos(-1.0);
 32 const int INF = 0x3f3f3f3f;
 33 const int MOD = 1e9 + 7;
 34 const double EPS = 1e-9;
 35 
 36 /*
 37 #include <ext/pb_ds/assoc_container.hpp>
 38 #include <ext/pb_ds/tree_policy.hpp>
 39 
 40 using namespace __gnu_pbds;
 41 tree<pli, null_type, greater<pli>, rb_tree_tag, tree_order_statistics_node_update> T;
 42 */
 43 
 44 struct Point {
 45     double x, y;
 46     Point () {}
 47     Point (double x, double y) : x(x), y(y) {}
 48     double operator ^ (const Point &p) const {
 49         return x * p.y - y * p.x;
 50     }
 51     Point operator - (const Point &p) const {
 52         return Point(x - p.x, y - p.y);
 53     }
 54     bool operator == (const Point &p) const {
 55         return x == p.x && y == p.y;
 56     }
 57     bool operator < (const Point &p) const {
 58         return y == p.y ? x < p.x : y < p.y;
 59     }
 60     void input() {
 61         scanf("%d", &x);
 62         scanf("%d%d", &x, &y);
 63     }
 64     void output() {
 65         printf("%d %d
", x, y);
 66     }
 67     double dis(const Point &p) const {
 68         return sqrt((x - p.x) * (x - p.x) + (y - p.y) * (y - p.y));
 69     }
 70 } p[13][5], pp;
 71 bool cmp(const Point &p1, const Point &p2) {
 72     ll v = (p1 - pp) ^ (p2 - pp);
 73     if (v) return v > 0;
 74     return abs(p1.x - pp.x) + abs(p1.y - pp.y) < abs(p2.x - pp.x) + abs(p2.y - pp.y);
 75 }
 76 int cross(Point pp, Point p1, Point p2) {
 77     return ((p1 - pp) ^ (p2 - pp)) > EPS;
 78 }
 79 struct Seg {
 80     Point s, e;
 81     Seg () {}
 82     Seg (Point s, Point e) : s(s), e(e) {}
 83     bool cross(Point p1, Point p2) {
 84         return ((p2 - p1) ^ (s - p1)) * ((p2 - p1) ^ (e - p1)) < EPS;
 85     }
 86 } ss[23][5];
 87 bool cross_Seg(Seg s1, Seg s2) {
 88     return s1.cross(s2.s, s2.e) && s2.cross(s1.s, s1.e);
 89 }
 90 int n, cnt[23];
 91 double dp[23][5];
 92 int main() {
 93     while (~scanf("%d", &n) && ~n) {
 94         for (int i = 1; i <= n; ++i) {
 95             double x, y;
 96             scanf("%lf", &x);
 97             for (int j = 1; j <= 4; ++j) {
 98                 scanf("%lf", &y);
 99                 p[i][j] = Point(x, y);
100             }
101             cnt[i] = 4;
102             ss[i][1] = Seg(Point(x, 0), p[i][1]);
103             ss[i][2] = Seg(p[i][2], p[i][3]);
104             ss[i][3] = Seg(p[i][4], Point(x, 10));
105         }
106         cnt[0] = cnt[n + 1] = 1;
107         p[0][1] = Point(0, 5);
108         p[n + 1][1] = Point(10, 5);
109         dp[0][1] = 0;
110         for (int i = 1; i <= n + 1; ++i) {
111             for (int j = 1; j <= cnt[i]; ++j) {
112                 dp[i][j] = INF;
113             }
114         }
115         for (int i = 1; i <= n + 1; ++i) {
116             for (int j = 1; j <= cnt[i]; ++j) {
117                 for (int k = 0; k < i; ++k) {
118                     for (int l = 1; l <= cnt[k]; ++l) {
119                         Seg ts = Seg(p[i][j], p[k][l]);
120                         int f = 1;
121                         for (int o = k + 1; o < i; ++o) {
122                             for (int _ = 1; _ <= 3; ++_) {
123                                 if (cross_Seg(ts, ss[o][_])) {
124                                     f = 0;
125                                     break;
126                                 }
127                             }
128                         }
129                         if (f) {
130                             dp[i][j] = min(dp[i][j], dp[k][l] + p[i][j].dis(p[k][l]));
131                         }
132                     }
133                 }
134             }
135         }
136         printf("%.2f
", dp[n + 1][1]);
137     }
138     return 0;
139 }
View Code

H: POJ 1113

题意:对于一个多边形,要筑一个围墙,使多边形上每个点到墙的距离都不超过L。求围墙最短长度。

思路:实际距离就是凸包长度加上一个半径为l的圆的周长。套凸包板子即可。

  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 mp make_pair
 29 #define clr(a, x) memset(a, x, sizeof(a))
 30 
 31 const double pi = acos(-1.0);
 32 const int INF = 0x3f3f3f3f;
 33 const int MOD = 1e9 + 7;
 34 const double EPS = 1e-9;
 35 
 36 /*
 37 #include <ext/pb_ds/assoc_container.hpp>
 38 #include <ext/pb_ds/tree_policy.hpp>
 39 
 40 using namespace __gnu_pbds;
 41 tree<pli, null_type, greater<pli>, rb_tree_tag, tree_order_statistics_node_update> T;
 42 */
 43 
 44 struct Point {
 45     int x, y;
 46     Point () {}
 47     Point (int x, int y) : x(x), y(y) {}
 48     ll operator ^ (const Point &p) const {
 49         return x * p.y - y * p.x;
 50     }
 51     Point operator - (const Point &p) const {
 52         return Point(x - p.x, y - p.y);
 53     }
 54     bool operator == (const Point &p) const {
 55         return x == p.x && y == p.y;
 56     }
 57     bool operator < (const Point &p) const {
 58         return y == p.y ? x < p.x : y < p.y;
 59     }
 60     void input() {
 61         scanf("%d%d", &x, &y);
 62     }
 63     void output() {
 64         printf("%d %d
", x, y);
 65     }
 66     double dis(const Point &p) const {
 67         return sqrt((x - p.x) * (x - p.x) + (y - p.y) * (y - p.y));
 68     }
 69 } p[1015], pp;
 70 bool cmp(const Point &p1, const Point &p2) {
 71     if (pp == p1) return true;
 72     if (pp == p2) return false;
 73     ll v = (p1 - pp) ^ (p2 - pp);
 74     if (v) return v > 0;
 75     return abs(p1.x - pp.x) + abs(p1.y - pp.y) < abs(p2.x - pp.x) + abs(p2.y - pp.y);
 76 }
 77 int n, l;
 78 stack<Point> sta;
 79 vector<Point> vec;
 80 int main() {
 81     scanf("%d%d", &n, &l);
 82     for (int i = 1; i <= n; ++i) {
 83         p[i].input();
 84     }
 85     pp = p[1];
 86     for (int i = 2; i <= n; ++i) {
 87         if (p[i] < pp) {
 88             pp = p[i];
 89         }
 90     }
 91     sort(p + 1, p + n + 1, cmp);
 92     sta.push(p[1]), sta.push(p[2]);
 93     for (int i = 3; i <= n; ++i) {
 94         while (sta.size() > 1) {
 95             Point p1 = sta.top(); sta.pop();
 96             Point p2 = sta.top(); 
 97             if (((p[i] - p2) ^ (p1 - p2)) < 0) {
 98                 sta.push(p1);
 99                 break;
100             }
101         }
102         sta.push(p[i]);
103     }
104     while (sta.size()) {
105         vec.pb(sta.top()); sta.pop();
106     }
107     for (int i = (int)vec.size() - 1; ~i; --i) {
108         //vec[i].output();
109     }
110     double ans = 0;
111     for (int i = 0; i < vec.size(); ++i) {
112         int j = (i + 1) % vec.size();
113         ans += vec[i].dis(vec[j]);
114     }
115     ans += 2 * pi * l;
116     printf("%.0f
", ans);    
117     return 0;
118 }
View Code

I:POJ 2653

思路:注意到在顶部的线段小于1000.于是我们每次加入线段时,扫一遍所有在顶部的线段,如果相交,那他就不再是顶部了,从这个集合中删去。可以用链表维护这个东西。复杂度O(1000n)。

 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 mp make_pair
29 #define clr(a, x) memset(a, x, sizeof(a))
30 
31 const double pi = acos(-1.0);
32 const int INF = 0x3f3f3f3f;
33 const int MOD = 1e9 + 7;
34 const double EPS = 1e-9;
35 
36 struct point {
37     double x, y;
38     point () {}
39     point (double x, double y) : x(x), y(y) {}
40     void input() {
41         scanf("%lf%lf", &x, &y);
42     }
43 };
44 struct segment {
45     point p1, p2;
46     segment () {}
47     segment (point p1, point p2) : p1(p1), p2(p2) {}
48     void input() {
49         p1.input();
50         p2.input();
51     }
52 } seg[100015];
53 double cross_mul(point p1, point p2, point p3) {
54     return (p2.x - p1.x) * (p3.y - p1.y) - (p3.x - p1.x) * (p2.y - p1.y);
55 }
56 bool cross(segment s1, segment s2) {
57     return cross_mul(s1.p1, s1.p2, s2.p1) * cross_mul(s1.p1, s1.p2, s2.p2) <= EPS && 
58            cross_mul(s2.p1, s2.p2, s1.p1) * cross_mul(s2.p1, s2.p2, s1.p2) <= EPS;
59 }
60 list<int> ans;
61 int n;
62 int main() {
63     while (~scanf("%d", &n) && n) {
64         ans.clear();
65         for (int i = 1; i <= n; ++i) {
66             seg[i].input();
67             for (list<int>::iterator it = ans.begin(); it != ans.end();) {
68                 int x = *it;
69                 if (cross(seg[x], seg[i])) {
70                     ans.erase(it++);
71                 } else {
72                     ++it;
73                 }
74             }
75             ans.pb(i);
76         }
77         printf("Top sticks:");
78         for (list<int>::iterator it = ans.begin(); it != ans.end();) {
79             printf(" %d", *it);
80             putchar(++it == ans.end() ? '.' : ',');
81         }
82         puts("");
83     }
84     return 0;
85 }
View Code

J:HDU 6325

题意:求字典序最小上凸包。

思路:选最左边的点,按x排序正常跑凸包的基础上注意两点:

位置相同的点直接取id小的

凸包上共线的点中间的点选或不选由线上的后继点的id大小决定。比较大小进行取舍。

  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 mp make_pair
 29 #define clr(a, x) memset(a, x, sizeof(a))
 30 
 31 const double pi = acos(-1.0);
 32 const int INF = 0x3f3f3f3f;
 33 const int MOD = 1e9 + 7;
 34 const double EPS = 1e-9;
 35 
 36 /*
 37 #include <ext/pb_ds/assoc_container.hpp>
 38 #include <ext/pb_ds/tree_policy.hpp>
 39 
 40 using namespace __gnu_pbds;
 41 tree<pli, null_type, greater<pli>, rb_tree_tag, tree_order_statistics_node_update> T;
 42 */
 43 
 44 struct Point {
 45     ll x, y;
 46     int id;
 47     Point () {}
 48     Point (int x, int y) : x(x), y(y) {}
 49     ll operator ^ (const Point &p) const {
 50         return x * p.y - y * p.x;
 51     }
 52     Point operator - (const Point &p) const {
 53         return Point(x - p.x, y - p.y);
 54     }
 55     bool operator == (const Point &p) const {
 56         return x == p.x && y == p.y;
 57     }
 58     bool operator < (const Point &p) const {
 59         return x == p.x ? id > p.id : x < p.x;
 60     }
 61     void input(int i) {
 62         id = i;
 63         scanf("%lld%lld", &x, &y);
 64     }
 65     void output() {
 66         printf("%lld %lld
", x, y);
 67     }
 68     double dis(const Point &p) const {
 69         return sqrt((x - p.x) * (x - p.x) + (y - p.y) * (y - p.y));
 70     }
 71 } p[200015], pp;
 72 ll cross(Point pp, Point p1, Point p2) {
 73     return ((p1 - pp) ^ (p2 - pp));
 74 }
 75 int T, n;
 76 deque<int> que;
 77 int main() {
 78     scanf("%d", &T);
 79     while (T--) {
 80         scanf("%d", &n);
 81         for (int i = 1; i <= n; ++i) {
 82             p[i].input(i);
 83         }
 84         sort(p + 1, p + n + 1);
 85         que.pb(1), que.pb(2);
 86         for (int i = 3; i <= n; ++i) {
 87             while (que.size() > 1) {
 88                 int x = que.back(); que.pop_back();
 89                 if (p[x] == p[i]) continue;
 90                 int y = que.back();
 91                 ll v = cross(p[y], p[i], p[x]);
 92                 if (v < 0) continue;
 93                 if (!v && p[i].id < p[x].id) continue;
 94                 que.pb(x);
 95                 break;
 96             }
 97             que.pb(i);
 98         }
 99         printf("1"); que.pop_front();
100         while (que.size()) {
101             printf(" %d", p[que.front()].id); que.pop_front();
102         }
103         puts("");
104     }
105     return 0;
106 }
View Code

K:CodeForces - 603D

题意:平面上n个线,形成一坨交点,问多少个三角形外接圆经过圆心。

思路:等价于圆心向所有直线做垂足,问多少个三元垂足对共线。

额外注意double可能丢精度,用两个整数存有理数。

 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 <iomanip>
16 #include <cctype>
17 #include <cassert>
18 #include <bitset>
19 #include <ctime>
20 
21 using namespace std;
22 
23 #define pau system("pause")
24 #define ll long long
25 #define pll pair<ll, ll>
26 #define pb push_back
27 #define mp make_pair
28 #define clr(a, x) memset(a, x, sizeof(a))
29 
30 const double pi = acos(-1.0);
31 const int INF = 0x3f3f3f3f;
32 const int MOD = 1e9 + 7;
33 const double EPS = 1e-9;
34 
35 int n, a[2015], b[2015], c[2015];
36 ll px[2015], qx[2015], py[2015], qy[2015], rx, ry;
37 ll gcd(ll x, ll y) {while (y) y ^= x ^= y ^= x %= y; return x;}
38 int flag;
39 map<pll, int> mmp;
40 ll ans = 0;
41 int main() {
42     scanf("%d", &n);
43     for (int i = 1; i <= n; ++i) {
44         scanf("%d%d%d", &a[i], &b[i], &c[i]);
45         if (!c[i]) ++flag;
46         px[i] = (ll)a[i] * c[i], py[i] = (ll)b[i] * c[i];
47         qx[i] = qy[i] = (ll)a[i] * a[i] + (ll)b[i] * b[i];
48     }
49     for (int i = 1; i <= n; ++i) {
50         if (!c[i]) continue;
51         mmp.clear();
52         for (int j = 1; j < i; ++j) {
53             if (!c[j]) continue;
54             rx = px[i] * qx[j] - px[j] * qx[i];
55             ry = py[i] * qy[j] - py[j] * qy[i];
56             ll g = gcd(rx, ry);
57             //printf("rx = %lld, ry = %lld, g = %lld
", rx, ry, g);
58             rx /= g, ry /= g;
59             if (rx < 0 || !rx && ry < 0) {
60                 rx = -rx;
61                 ry = -ry;
62             }
63             ++mmp[pll(rx, ry)];
64         }
65         for (map<pll, int>::iterator it = mmp.begin(); it != mmp.end(); ++it) {
66             ll x = (*it).second;
67             ans += x * (x - 1) >> 1;
68         }
69     }
70     if (2 == flag) ans += n - 2;
71     printf("%I64d
", ans);
72     return 0;
73 }
View Code

L:CodeForces - 975E 

题意:先不说了...

思路:我们只需维护重心位置以及每个点相对重心的关系。然后每次操作暴力模拟。码量较大。

  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 mp make_pair
 29 #define clr(a, x) memset(a, x, sizeof(a))
 30 
 31 const long double pi = acos(-1.0);
 32 const int INF = 0x3f3f3f3f;
 33 const int MOD = 1e9 + 7;
 34 const long double EPS = 1e-9;
 35 
 36 /*
 37 #include <ext/pb_ds/assoc_container.hpp>
 38 #include <ext/pb_ds/tree_policy.hpp>
 39 
 40 using namespace __gnu_pbds;
 41 tree<pli, null_type, greater<pli>, rb_tree_tag, tree_order_statistics_node_update> T;
 42 */
 43 
 44 int n, q;
 45 struct point {
 46     long double x, y;
 47     point() {}
 48     point (long double x, long double y) : x(x), y(y) {}
 49     void input() {
 50         //scanf("%lf%lf", &x, &y);
 51         cin >> x >> y;
 52     }
 53     void output() {
 54         double tx = x, ty = y;
 55         printf("%.12f %.12f
", tx, ty);
 56     }
 57     point operator - (const point &p) const {
 58         return point(x - p.x, y - p.y);
 59     }
 60     point operator + (const point &p) const {
 61         return point(x + p.x, y + p.y);
 62     }
 63     long double operator ^ (const point &p) const {
 64         return x * p.y - y * p.x;
 65     }
 66     point operator / (const long double &k) const {
 67         return point(x / k, y / k);
 68     }
 69     point operator * (const long double &k) const {
 70         return point(x * k, y * k);
 71     }
 72     long double dis(const point &p) const {
 73         return sqrt((x - p.x) * (x - p.x) + (y - p.y) * (y - p.y));
 74     }
 75 } p[100015];
 76 long double d0[100015], d1[100015], th[100015];
 77 long double cal_th(point p1, point p0, point p2) {
 78     long double th1 = atan2(p1.y - p0.y, p1.x - p0.x);
 79     long double th2 = atan2(p2.y - p0.y, p2.x - p0.x);
 80     long double res = th1 - th2;
 81     if (res < 0) res += 2 * pi;
 82     return res;
 83 }
 84 multiset<int> rem;
 85 point get_pos(int index) {
 86     long double th1 = atan2(p[1].y - p[0].y, p[1].x - p[0].x);
 87     long double th2 = th1 - th[index];
 88     if (th2 < 0) th2 += 2 * pi;
 89     return p[0] + point(d0[index] * cos(th2), d0[index] * sin(th2));
 90 }
 91 void rot_and_update(int index2) {
 92     point p2 = get_pos(index2);
 93     long double th01 = atan2(p[0].y - p2.y, p[0].x - p2.x);
 94     long double th02 = 3 * pi / 2;
 95     long double th0 = th02 - th01;
 96     if (th0 < 0) th0 += 2 * pi;
 97     long double th11 = atan2(p[1].y - p2.y, p[1].x - p2.x);
 98     //p[0].output(), p[1].output(), p2.output();
 99     long double th12 = th11 + th0;
100     if (2 * pi <= th12) th12 -= 2 * pi;
101     //printf("index2 = %d
", index2);
102     p[0] = point(p2.x, p2.y - d0[index2]);
103     p[1] = p2 + point(d1[index2] * cos(th12), d1[index2] * sin(th12));
104 }
105 void get_wp() {
106     long double s = 0;
107     p[0] = point(0, 0);
108     for (int i = 2; i < n; ++i) {
109         long double ts = (p[i] - p[1]) ^ (p[i] - p[i + 1]);
110         p[0] = p[0] + (p[1] + p[i] + p[i + 1]) / 3 * ts;
111         s += ts;
112     }
113     p[0] = p[0] / s;
114 }
115 int main() {
116     scanf("%d%d", &n, &q);
117     p[0] = point(0, 0);
118     for (int i = 1; i <= n; ++i) {
119         p[i].input();
120     }
121     get_wp();
122     for (int i = 1; i <= n; ++i) {
123         th[i] = cal_th(p[1], p[0], p[i]);
124         d0[i] = p[0].dis(p[i]);
125         d1[i] = p[1].dis(p[i]);
126     }
127     rem.insert(1), rem.insert(2);
128     while (q--) {
129         int op;
130         scanf("%d", &op);
131         if (1 == op) {
132             int f, t;
133             scanf("%d%d", &f, &t);
134             multiset<int>::iterator it = rem.lower_bound(f);
135             rem.erase(it);
136             int v = *rem.begin();
137             rot_and_update(v);
138             rem.insert(t);
139         } else {
140             int v;
141             scanf("%d", &v);
142             get_pos(v).output();
143         }
144     }
145     return 0;
146 }
147 /*
148 10 10
149 0 -100000000
150 1 -100000000
151 1566 -99999999
152 2088 -99999997
153 2610 -99999994
154 3132 -99999990
155 3654 -99999985
156 4176 -99999979
157 4698 -99999972
158 5220 -99999964
159 1 2 5
160 2 1
161 1 1 7
162 2 5
163 1 5 4
164 1 4 2
165 2 8
166 1 7 9
167 2 1
168 1 2 10
169 */
View Code
原文地址:https://www.cnblogs.com/BIGTOM/p/9512099.html