poj 2318

题意:给出一个矩形区域和n条分割线,将分出的$n+1$个区域从左向右从0到n编号,给出一些点,问落在每一个区域里的点的数量

计算几何裸题

由于题目中限制挡板不相交且从左向右给出,因此直接从左向右枚举每一个挡板,用叉积判断这个点在这个挡板的左侧还是右侧即可

具体的,我们记录每个挡板的下面的点的坐标和这个挡板的方向向量(方向从下指向上),然后对每个点计算由下面那个点指向这个点的向量,对这两个向量做叉积,如果值为正说明在左侧(由挡板向量逆时针旋转得目标向量,说明在挡板左侧)

小技巧:直接把最右端的边界作为一个挡板扔进去枚举可以避免一些分类讨论

贴代码:

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#define ll long long
using namespace std;
struct Point
{
    ll x,y;
};
struct Vec
{
    ll x,y;
};
struct Line
{
    Point a;
    Vec d;
}l[5005];
int ret[5005];
ll cross_mul(Vec a,Vec b)
{
    return a.x*b.y-a.y*b.x;
}
/*ll sgn(ll x)
{
    if(x>0)return 1;
    else if(x<0)return -1;
    return 0;
}*/
int n,m;
ll xx0,yy0,xx1,yy1;
int main()
{
    while(1)
    {
        memset(ret,0,sizeof(ret));
        scanf("%d",&n);
        if(!n)return 0;
        scanf("%d",&m);
        scanf("%lld%lld%lld%lld",&xx0,&yy0,&xx1,&yy1);
        for(int i=1;i<=n;i++)
        {
            ll xu,xd;
            scanf("%lld%lld",&xu,&xd);
            l[i].a.x=xd,l[i].a.y=yy1;
            l[i].d.x=xu-xd,l[i].d.y=yy0-yy1;
        }
        n++;
        l[n].a.x=xx1,l[n].a.y=yy1,l[n].d.x=0,l[n].d.y=yy0-yy1;
        for(int i=1;i<=m;i++)
        {
            ll qx,qy;
            scanf("%lld%lld",&qx,&qy);
            for(int j=1;j<=n;j++)
            {
                Vec tt;
                tt.x=qx-l[j].a.x,tt.y=qy-l[j].a.y;
                if(cross_mul(l[j].d,tt)>=0)
                {
                    ret[j-1]++;
                    break;
                }
            }
        }
        for(int i=0;i<n;i++)printf("%d: %d\n",i,ret[i]);
        printf("\n");
    }
    return 0;
}

 

posted @ 2019-06-05 21:24  lleozhang  Views(151)  Comments(0Edit  收藏  举报
levels of contents