题目链接: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:判断一个点是否在三角形内部可以用面积法。