题目链接:Click here~~
题意:
有一个矩形的盒子,中间插了n个挡板,将盒子分成n+1个区域,然后给m个点,问最后每个区域落下多少个点。(点不会落到挡板上)
解题思路:
把矩形的右边看成第n+1个挡板。
稍加分析,得到这个特点:若点 k 在挡板 i 的左边,那么 k 也一定在挡板 j 的左边(i < j <= n+1)。
则对于每一个点k,只要找到最小的挡板 i ,满足点 k 在挡板 i 的左边,则点 k 就在区域 i 中。
如此,即可转换成二分的模型来求解。
#include <math.h> #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define N 5005 const double eps = 1e-6; struct Point { int x,y; Point(){} Point(int x,int y):x(x),y(y){} }p,pp1,pp2,pp3,pp4; struct Rec { Point p1,p2,p3,p4; Rec(){} Rec(Point p1,Point p2,Point p3,Point p4):p1(p1),p2(p2),p3(p3),p4(p4){} }R[N]; int ans[N]; int sgn(double x) { return fabs(x)<eps ? 0 : (x > eps ? 1 : -1); } double Cross(const Point& p1,const Point& p2,const Point& p3,const Point& p4) { return (p2.x-p1.x)*(p4.y-p3.y) - (p2.y-p1.y)*(p4.x-p3.x); } double Area(const Point& p1,const Point& p2,const Point& p3) { return fabs(Cross(p1,p2,p1,p3)); } bool InTri(const Point& p,const Point& p1,const Point& p2,const Point& p3) { return Area(p,p1,p2) + Area(p,p2,p3) + Area(p,p3,p1) == Area(p1,p2,p3); } bool InRec(const Point& p,const Point& p1,const Point& p2,const Point& p3,const Point& p4) { return InTri(p,p1,p2,p3) || InTri(p,p1,p3,p4); } int Search(Point p,int l,int r) { while(l < r) { int mid = (l+r)/2; if(Cross(p,R[mid].p4,p,R[mid].p3) > 0) l = mid+1; else r = mid; } return r; } int main() { int n,m,x1,x2,minx,maxy,maxx,miny; bool first = true; while(scanf("%d",&n),n) { if(!first) puts(""); else first = false; memset(ans,0,sizeof(ans)); scanf("%d%d%d%d%d",&m,&minx,&maxy,&maxx,&miny); pp1 = Point(minx,maxy); pp2 = Point(minx,miny); for(int i=0;i<n;i++) { scanf("%d%d",&x1,&x2); pp3 = Point(x2,miny); pp4 = Point(x1,maxy); R[i] = Rec(pp1,pp2,pp3,pp4); pp1 = pp4 , pp2 = pp3; } R[n] = Rec(pp1,pp2,Point(maxx,miny),Point(maxx,maxy)); for(int i=0;i<m;i++) { scanf("%d%d",&p.x,&p.y); ans[Search(p,0,n)]++; } for(int i=0;i<=n;i++) printf("%d: %d\n",i,ans[i]); } return 0; }
Ps:判断一个点是否在三角形内部可以用面积法。