题意:在一个长方形区域用n条直线分隔成n+1个部分,给定m个点,求这个区域的m个点,求点所在的部分。
算法:二分搜索,点和直线的位置关系
1,设直线的方程ax+bx+c=0(a>0);若点(x0,y0)代入方程:
若ax0+by0+c<0,则点在直线的左侧;
若ax0+by0+c=0,则点在直线上;
若ax0+by0+c<0,则点在直线的右侧;
但是前提是a>0,否则结果左右对调(WA了一次).
2,(x1,y1)和(x2,y2)为某直线的两个点,直线的方程就可以表示为(y2-y1)(x-x1)-(x2-x1)(y-y1)=0;
因为n较大,而直线与直线对点具有序的关系,即点如果在某条直线的左侧,那么肯定在那条直线右侧所有的直线的左侧,
所以可用二分搜索把时间复杂度降为O(nlogn);
#include<cstdio> #include<cstring> #define MAXN 5010 using namespace std; int x,y,dy,n,x1,x2,y1,y2,dx[MAXN],Ui[MAXN]; int BSearch() { int lt,rt,mid; for(lt=-1,rt=n;lt+1<rt;) { mid=(lt+rt)>>1; if(dy*(x-Ui[mid])-dx[mid]*(y-y1)<0)//因为y1>y2,所以dy>0 rt=mid; else lt=mid; } return rt; } int main() { int m,i,Li,b[MAXN]; for(;scanf("%d",&n),n;) { memset(b,0,sizeof(b)); scanf("%d%d%d%d%d",&m,&x1,&y1,&x2,&y2); dy=y1-y2; for(i=0;i<n;i++) { scanf("%d%d",Ui+i,&Li); dx[i]=Ui[i]-Li; } for(;m--;) { scanf("%d%d",&x,&y); b[BSearch()]++; } for(i=0;i<=n;i++) printf("%d: %d\n",i,b[i]); puts(""); } return 0; }