题目大意:给你一个矩形的左上角和右下角的坐标,然后这个矩形有 N 个隔板分割成 N+1 个区域,下面有 M 组坐标,求出来每个区域包含的坐标数。
分析:做的第一道计算几何题目....使用叉积判断方向,然后使用二分查询找到点所在的区域。
代码如下:
============================================================================================================================
#include<stdio.h> #include<math.h> using namespace std; const int MAXN = 5e3+7; const double PI = acos(-1.0); struct point { double x, y; point(int x=0, int y=0):x(x), y(y){} }; struct Vector { point a, b; void InIt(point t1, point t2){a=t1, b=t2;} double operator * (const point &p) const { return (p.x-b.x)*(a.y-b.y) - (p.y-b.y)*(a.x-b.x); } }; Vector line[MAXN]; int Find(int N, point a) { int L=0, R=N; while(L <= R) { int Mid = (L+R) >> 1; if(line[Mid] * a < 0) R = Mid - 1; else L = Mid + 1; } return R; } int main() { int M, N; double x1, x2, y1, y2, ui, li; while(scanf("%d", &N) != EOF && N) { scanf("%d%lf%lf%lf%lf", &M, &x1, &y1, &x2, &y2); int ans[MAXN]={0}; line[0].InIt(point(x1, y1), point(x1, y2)); for(int i=1; i<=N; i++) { scanf("%lf%lf", &ui, &li); line[i].InIt(point(ui, y1), point(li, y2)); } while(M--) { scanf("%lf%lf", &ui, &li); int i = Find(N, point(ui, li)); ans[i] += 1; } for(int i=0; i<=N; i++) printf("%d: %d ", i, ans[i]); printf(" "); } return 0; }
重写...
#include<math.h> #include<stdio.h> #include<vector> #include<iostream> #include<algorithm> using namespace std; const double EPS = 1e-5; const int maxn = 5005; int SIGN(const double &val) {///整数返回1,负数返回-1, 0返回0 if(val > EPS)return 1; if(fabs(val) < EPS)return 0; return -1; } class Point { public: Point(double x, double y): x(x), y(y){} Point operator- (const Point& other)const {///重载减号 return Point((x-other.x), (y - other.y)); } double operator^(const Point& other)const {///重载异或,定义叉积的运算 return (x*other.y) - (y*other.x); } public: double x, y; }; class Segment { public: Segment(Point S, Point E) : S(S), E(E){} int Mul(Point& other) const {///用差乘判断点在线段的方向 return SIGN( (E-S)^(other-S) ); } public: Point S, E; }; class SetSegment {///定义一个线段的集合,有很多线段构成 public: void Insert(const Segment& other) {///插入一个线段 segs.push_back(other); } unsigned int Find(Point p) {///查找点p靠近的最左边的线段的下标 unsigned int L=0, R=segs.size()-1, M; while(L <= R) { M = (L+R) / 2; Segment tmp = segs[M]; if(tmp.Mul(p) == -1) R = M-1; else L = M+1; } return R; } public: vector<Segment> segs; }; int main() { int N, M; double x1, x2, y1, y2, Ui, Li; while(scanf("%d", &N) != EOF && N) { scanf("%d%lf%lf%lf%lf", &M, &x1, &y1, &x2, &y2); SetSegment ss; ss.Insert(Segment(Point(x1, y1), Point(x1, y2))); for(int i=0; i<N; i++) { scanf("%lf%lf", &Ui, &Li); ss.Insert(Segment(Point(Ui, y1), Point(Li, y2))); } int ans[maxn] = {0}; while(M--) { scanf("%lf%lf", &x1, &y1); int index = ss.Find(Point(x1, y1)); ans[index] += 1; } for(int i=0; i<=N; i++) printf("%d: %d ", i, ans[i]); printf(" "); } return 0; }