您的位置:首页 > 其它

ACM练级日志:POJ 2318 叉积的简单应用

2014-08-09 22:33 127 查看
最近开始学习计(keng)算(die)几何,第一道入门题就是这道了。

本题最核心的问题,就是如何判断一个点在直线(线段)的什么位置。这一点叉积可以很容易地做到。

设直线(线段)的向量为S->E, 询问点为P, 那么我们只需要计算一下 S->P x S->E, 如果大于0,说明S->P 顺时针旋转会达到S->E, 等于0说明就在直线上,小于0说明它需要逆时针旋转才能达到S->E。

在这道题里,如果我们始终选择S是上面的点,E是下面的点的话,那么S->P如果顺时针旋转能达到S->E,说明P在这条线段左边,就满足要求了。用叉积判断的时候,大于0小于0跟你所选的向量起终点以及谁x谁都有关系,最后判出顺时针逆时针也需要自己想想是在直线的哪边……

最后是代码,第一次写,可能还比较丑陋……

#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
using namespace std;

typedef long long LL;

struct ptype
{
LL x,y;
ptype(){x=0; y=0;};

ptype(LL _x, LL _y)
{
x=_x;
y=_y;
}
ptype operator + (ptype p)
{
return ptype(x+p.x , y+p.y);
}
ptype operator - (ptype p)
{
return ptype(x-p.x, y-p.y);
}
LL cross(ptype p)
{
return x * p.y - y * p.x;
}
};

struct segtype
{
ptype s,e;
};

int n,m;
LL box_x0, box_y0, box_x1, box_y1;
segtype seg[5010];
int ans[5010];

void init()
{
memset(seg, 0 , sizeof(seg));
memset(ans, 0, sizeof(ans));
return;
}

int main()
{
while(true)
{
scanf("%d", &n);
if(n==0)
break;
scanf("%d %I64d %I64d %I64d %I64d", &m, &box_x0, &box_y0, &box_x1, &box_y1);

init();

int i;
for(i=1;i<=n;i++)
{
LL tx1, tx2;
scanf("%I64d %I64d", &tx1, &tx2);
ptype s(tx1, box_y0);
ptype e(tx2, box_y1);

seg[i].s = s;
seg[i].e = e;

}

for(i=1;i<=m;i++)
{
LL tx1, tx2;
scanf("%I64d %I64d", &tx1, &tx2);
ptype now(tx1, tx2);

int low=1, high=n+1;
while(low < high)
{
int mid = (high+low)/2;
ptype seg_s = seg[mid].s;
ptype seg_e = seg[mid].e;

ptype line(seg_e - seg_s);
ptype now_vec(now - seg_s);

if( now_vec.cross(line) > 0)
high = mid;
else
low = mid+1;
}

ans[high]++;

}

for(i=1;i<=n+1;i++)
{
printf("%d: %d\n", i-1, ans[i]);
}
printf("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: