[POJ2318]TOYS (计算几何 行列式(叉乘)+二分)

题目链接:http://poj.org/problem?id=2318

题意大致是给了m个玩具,这m个玩具在n+1个盒子里。坐标给定,求每个盒子里有多少个玩具。

简单考虑就是判断点在线段的哪一侧,二分+判断即可。

方法1:在BJTU集训队课件上看到的:

检查线段p1p3是在线段p1p2的顺时针方向还是逆时针方向
计算(p3–p1)x(p2–p1)

 

方法2:学堂在线上邓俊辉老师开的计算几何课程讲了一个用行列式的方法,具体证明可以参考计算几何这门课程。

判断p2点在直线p1p3的左侧还是右侧:
|p1.x p1.y 1|
|p3.x p3.y 1|
|p2.x p2.y 1|

 

泛型在调用的时候特别麻烦,回头改成用宏替换好了。代码如下:

  1 #include <algorithm>
  2 #include <iostream>
  3 #include <iomanip>
  4 #include <cstring>
  5 #include <climits>
  6 #include <complex>
  7 #include <fstream>
  8 #include <cassert>
  9 #include <cstdio>
 10 #include <bitset>
 11 #include <vector>
 12 #include <deque>
 13 #include <queue>
 14 #include <stack>
 15 #include <ctime>
 16 #include <set>
 17 #include <map>
 18 #include <cmath>
 19 
 20 using namespace std;
 21 
 22 template<typename pp>
 23 struct Point {
 24     pp x;
 25     pp y;
 26     Point(){}
 27     Point(pp xx, pp yy) : x(xx), y(yy) {}
 28 };
 29 
 30 
 31 template<typename pp>
 32 struct Line {
 33     Point<pp> u;
 34     Point<pp> v;
 35     Line() {}
 36     Line(Point<pp> uu, Point<pp> vv) : u(uu), v(vv) {}
 37 };
 38 
 39 /*
 40 检查线段p1p3是在线段p1p2的顺时针方向还是逆时针方向
 41 计算(p3–p1)x(p2–p1)
 42 */
 43 template<typename pp>
 44 pp direction1(Point<pp> p1, Point<pp> p2, Point<pp> p3) { // >0右拐 <0左拐
 45     return (p3.x-p1.x)*(p2.y-p1.y)-(p2.x-p1.x)*(p3.y-p1.y);
 46 }
 47 
 48 /*
 49 |p1.x p1.y 1|
 50 |p3.x p3.y 1|
 51 |p2.x p2.y 1|
 52 */
 53 template<typename pp>
 54 pp direction2(Point<pp> p1, Point<pp> p2, Point<pp> p3) { // >0右拐 <0左拐
 55     return (p1.x*p3.y+p1.y*p2.x+p3.x*p2.y)-(p2.x*p3.y+p1.x*p2.y+p1.y*p3.x);
 56 }
 57 
 58 
 59 const int maxn = 6666;
 60 int n, m;
 61 int ex1, ey1, ex2, ey2;
 62 Line<int> line[maxn];
 63 int ans[maxn];
 64 
 65 int main() {
 66     // freopen("in", "r", stdin);
 67     int flg = 1;
 68     while(~scanf("%d", &n) && n) {
 69         memset(ans, 0, sizeof(ans));
 70         scanf("%d %d %d %d %d", &m, &ex1, &ey1, &ex2, &ey2);
 71         int Ui, Li;
 72         for(int i = 0; i < n; i++) {
 73             scanf("%d %d", &Ui, &Li);
 74             line[i] = Line<int>(Point<int>(Ui, ey1), Point<int>(Li, ey2));
 75         }
 76         line[n] = Line<int>(Point<int>(ex2, ey1), Point<int>(ex2, ey2));
 77         int x, y;
 78         Point<int> p;
 79         while(m--) {
 80             scanf("%d %d", &x, &y);
 81             p = Point<int>(x, y);
 82             int ll = 0, rr = n;
 83             int tmp;
 84             while(ll <= rr) {
 85                 int mm = (ll + rr) >> 1;
 86                 if(direction1<int>(p, line[mm].u, line[mm].v) > 0) {
 87                     tmp = mm;
 88                     rr = mm - 1;
 89                 }
 90                 else ll = mm + 1;
 91             }
 92             ans[tmp]++;
 93         }
 94         flg ? flg = 0 : printf("\n");
 95         for(int i = 0; i <= n; i++) {
 96             printf("%d: %d\n", i, ans[i]);
 97         }
 98     }
 99     return 0;
100 }

 

你可能感兴趣的:([POJ2318]TOYS (计算几何 行列式(叉乘)+二分))