POJ2318 (TOYS)[计算几何]

·· / ·– ·· ·-·· ·-·· / ·–· · ·-· ··· ·· ··· - / ··- -· - ·· ·-·· / ·· / ·– ·· -·
题目链接:http://poj.org/problem?id=2318
这题是计算几何题,需要用到叉积判断点在线段的左边还是右边。
暴力的话n^2的复杂度应该会超时,这里用了二分的方法。把地图的左右边界各自作为一条直线插入,并且考虑到存在点落在边界的情况,这两条新加的直线要对应向地图外偏移一点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
const double eps = 1e-8;
const double inf = 1e20;
int sgn(double x) {
if (fabs(x) < eps) return 0;
if (x < 0) return -1;
else return 1;
}
struct Point {
double x, y;
Point() {}
Point(double _x, double _y) {
x = _x;
y = _y;
}
void input() {
scanf("%lf%lf", &x, &y);
}
Point operator - (const Point &b) const {
return Point(x - b.x, y - b.y);
}
double operator ^ (const Point &b) const {
return x * b.y - y * b.x;
}
};
struct Line {
Point s, e;
Line() {}
Line(Point _s, Point _e) {
s = _s;
e = _e;
}
void input(int x1, int y1, int x2, int y2) {
s.x = x1;
s.y = y1;
e.x = x2;
e.y = y2;
}
int relation(Point p) {
int c = sgn((p-s) ^ (e-s));
if (c < 0) return 1;
else if (c > 0) return 2;
else return 3;
}
};
const int maxn = 5000 + 10;
int n, m;
Line lines[maxn];
int cnt[maxn];
bool check(int mid, Point now) {
if (lines[mid].relation(now) == 2) return 1;
else return 0;
}
int main() {
int x1, y1, x2, y2;
int U, L;
while(scanf("%d", &n)!=EOF && n) {
memset(cnt, 0, sizeof(cnt));
scanf("%d", &m);
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
lines[0].input(x1-1, y1, x1-1, y2);
lines[n+1].input(x2+1, y1, x2+1, y2);
for(int i = 1; i <= n; i++) {
scanf("%d%d", &U, &L);
lines[i].input(U, y1, L, y2);
}
for(int i = 0; i < m; i++) {
Point now;
now.input();
int l = 0, r = n + 1;
while(l < r-1) {
int mid = (l+r) >> 1;
if (check(mid, now)) r = mid;
else l = mid;
}
cnt[l]++;
}
for(int i = 0; i <= n; i++)
printf("%d: %d\n", i, cnt[i]);
printf("\n");
}
}