传送门
计算几何基础题——第一题
这个题需要用到的有:
1.向量
2.向量基本运算(加减法)
3.向量叉积
(https://wenku.baidu.com/view/6d53cdcd58f5f61fb73666c6.html)
(http://blog.csdn.net/hc14519/article/details/50716299)
(第一篇是ppt,必须看,讲的非常基础)
(第二篇是关于向量叉积的几何意义的讲解,虽然讲的一般,但还是可以看看)
(还有,其实叉积的几何意义可以说成这样:
(P×Q就是0,P,Q,P+Q围成的四边形的面积,带符号)
(再补充三个。。)
(http://www.matrix67.com/blog/archives/6217)
(http://www.yalewoo.com/in_triangle_test.html)
(http://blog.sina.com.cn/s/blog_4c70701801013e49.html)
4.二分法
大家学会之后再来做,相信你就会了。
关于如何用叉积判断点在直线哪一侧:
首先要知道怎么以一个点为坐标原点建立坐标系:
其实只要将所有向量减去它就好了
然后我们可以用叉积判断一个点在另一个点的顺时针还是逆时针
设向量P,Q(可抽象为坐标系上的点)
Cross(P,Q)<0,则P在Q的逆时针方向
Cross(P,Q)=0,则P,Q在同一直线上
Cross(P,Q)>0,则P在Q的顺时针方向
然后利用这个就可以判断了
然后我们就可以二分了。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#define ll long long
using namespace std;
inline int read(){
int x=0;char ch=' ';int f=1;
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
const int N=5005;
const double eps=1e-12;
struct Point{
double x,y;
Point(){}
Point(double _x,double _y):x(_x),y(_y){}
inline Point operator - (const Point& b) const {return Point(x-b.x,y-b.y);}
};
struct Line{
Point s,t;
Line(){}
Line(Point _s,Point _t):s(_s),t(_t){}
}L[N];
inline int dcmp(double x){
if(fabs(x)<eps)return 0;
return x>eps?1:-1;
}
inline double Cross(const Point& a,const Point& b){
return a.x*b.y-a.y*b.x;
}
inline int check(Line L,Point P){
Point P1=L.s-P,P2=L.t-P;
return dcmp(Cross(P1,P2));
}
int n,m,ans[N];
double X1,X2,Y1,Y2;
int main(){
while(1){
memset(ans,0,sizeof(ans));
n=read();if(!n)break;m=read();
scanf("%lf %lf %lf %lf",&X1,&Y1,&X2,&Y2);
for(int i=1;i<=n;i++){
scanf("%lf",&L[i].t.x);L[i].t.y=Y1;
scanf("%lf",&L[i].s.x);L[i].s.y=Y2;
}
for(int i=1;i<=m;i++){
Point Ask;scanf("%lf %lf",&Ask.x,&Ask.y);
int l=0,r=n,mid;
while(l<r){
mid=(l+r+1)>>1;
if(check(L[mid],Ask)==-1)l=mid;
else r=mid-1;
}
ans[l]++;
}
for(int i=0;i<=n;i++)printf("%d: %d\n",i,ans[i]);
putchar('\n');
}
return 0;
}