POJ 2308 TOYS

题意:在一个长方形区域用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;
}
原文地址:https://www.cnblogs.com/xchaos/p/2465060.html