您的位置:首页 > 其它

poj2318_TOYS_叉积判断点在线段的哪一侧

2017-07-19 11:51 253 查看

题意

在一个矩形盒子中,有 n 条线段,一个端点在矩形的上边,一个端点在矩形的下边,且互不相交。这 n 条线段把盒子分成 n + 1 个区域。给出 m 个玩具的坐标,问每个区域中有多少个玩具。

思路

整体上用二分法。枚举边,判断点在边的哪一侧,缩小范围,最终求出解。如果用每个区间的右界来界定区域,那么问题就转化成了 求某点右侧的边中最靠左的那一条,显然是二分的思路。

关键点就是如何判断点在边的哪一侧,这里用向量的叉积来判断。

叉积判断点在线段的哪一侧

从点出发,向线段的上端点作一向量 v1, 下端点作一向量 v2,计算 v1 v2 的叉积。

若 v1 ^ v2 < 0 ,在左侧;

若 v1 ^ v2 > 0 , 在右侧。

可以借助右手定则直观地判断。

题目链接

http://poj.org/problem?id=2318

AC代码

#include<iostream>
#include<cstdio>
#include<cstring>

using namespace std;

const int maxn = 5000 + 10;

struct P
{
int x, y;

P(){}
P(int _x, int _y):x(_x), y(_y){}

P operator - (P b)
{
return P(x - b.x, y - b.y);
}
int operator ^ (P b)
{
return x * b.y - b.x * y;
}
};

struct L
{
P l, r;
L(){}
L(P _l, P _r):l(_l), r(_r){}
};

int n, m, x1, y1, x2, y2;                                   //边数,玩具数,左上角,右下角
L line[maxn];                                               //边集
int cnt[maxn];                                              //计数

int Xmult(P d, int t)
{
return (d - line[t].l) ^ (d - line[t].r);
}

int main()
{
while(1)
{
scanf("%d", &n);
if(n == 0) break;
scanf("%d %d %d %d %d", &m, &x1, &y1, &x2, &y2);

for(int i= 0; i< n; i++)                            //用每个区域的右界来界定这个区域
{
int u, l;
scanf("%d %d", &u, &l);
line[i] = L(P(u, y1), P(l, y2));
}
line
= L(P(x2, y1), P(x2, y2));                  //共 n + 1 个区域

memset(cnt , 0 ,sizeof cnt);
while(m --)
{
int x, y;
scanf("%d %d", &x, &y);
P d = P(x, y);

int lb = 0, ub = n;                             //二分
while(lb <= ub)
{
int mid = (lb + ub) >> 1;

if(Xmult(d, mid) < 0)                       //叉积判断在哪一侧,实际上是求点右侧的边中最靠左的
ub = mid - 1;                           //在左侧,缩小范围
else lb = mid + 1;                          //在右侧,缩小范围
}

cnt[lb] ++;                                 //计数
}

for(int i= 0; i<= n; i++)
printf("%d: %d\n", i, cnt[i]);
printf("\n");
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: