计算几何(一):叉积的简单应用
2012-09-14 19:48
176 查看
这是学习《ACM-ICPC程序设计系列—计算几何》自己AC的第一个计算几何的问题。题目是比较简单的,但还是花了我很久的时间。
题目可以抽象成:一个长方形被n条不相交的线段分隔成n+1个区间,给定m个点的坐标,计算出每个区间里各有多少个点。
需要注意的是:输入时,分隔长方形的线段已经排序。(这意味着可以用二分查找)
我的思路很简单:把区间构造起来,(这里我把长方形比喻为盒子,中间加入的线段我称作隔板。)然后,每个点去二分搜索,找到自己处在的区间就OK了。最后输出结果。
这里面的难点就在于:我们怎么去判断一个点在一条线段的左侧还是右侧呢?这就要用到向量叉积。叉积的一个非常重要的性质是通过它的符号判断两向量相互之间的顺逆时针关系:设向量P=(x1,y1),Q=(x2,y2)
如果P*Q>0则P在Q的顺时针方向;
如果P*Q=0则P与Q共线,可能同向,与可能反向;
如果P*Q<0则P在Q的逆时针方向。
(请注意这里是叉乘)
这道题在几何上就考了这一个知识点,如果我们一步一步来,理清关系,其实是很简单的!
代码:
题目可以抽象成:一个长方形被n条不相交的线段分隔成n+1个区间,给定m个点的坐标,计算出每个区间里各有多少个点。
需要注意的是:输入时,分隔长方形的线段已经排序。(这意味着可以用二分查找)
我的思路很简单:把区间构造起来,(这里我把长方形比喻为盒子,中间加入的线段我称作隔板。)然后,每个点去二分搜索,找到自己处在的区间就OK了。最后输出结果。
这里面的难点就在于:我们怎么去判断一个点在一条线段的左侧还是右侧呢?这就要用到向量叉积。叉积的一个非常重要的性质是通过它的符号判断两向量相互之间的顺逆时针关系:设向量P=(x1,y1),Q=(x2,y2)
如果P*Q>0则P在Q的顺时针方向;
如果P*Q=0则P与Q共线,可能同向,与可能反向;
如果P*Q<0则P在Q的逆时针方向。
(请注意这里是叉乘)
这道题在几何上就考了这一个知识点,如果我们一步一步来,理清关系,其实是很简单的!
代码:
/* * poj_2318.cpp * * Created on: 规定上面是起点,下面是终点;左面是起点,右面是终点 * Author: Administrator */ #include<stdio.h> #include<string.h> #define M 5005 struct Point{ double x,y; }; struct Segment{ Point start,end; }; int bin[M]; Segment box[M];//表示盒子 int n,m; double x1,y1,x2,y2;//表示盒子最外面的边框 /* *点p置于线段s的哪一侧:0 左侧,1 右侧 * */ int isLeft(const Point &p,const Segment &s){ double ans; ans=(p.x-s.end.x)*(s.start.y-s.end.y)-(s.start.x-s.end.x)*(p.y-s.end.y); if(ans<0)return 1; else if(ans>0)return 0; else{printf("ERROR!\n"); return -1;} } //检查这个点是否在盒子里面 bool inside(Point p){ if(p.x>x2||p.x<x1||p.y<y2||p.y>y1) return false; return true; } //盒子中加入隔板 void add(const double &x1,const double &y1,const double &x2,const double &y2, int i){ box[i].start.x=x1;box[i].start.y=y1; box[i].end.x=x2;box[i].end.y=y2; } //查找玩具对应的格子:因为已经排序,所以可以用二分查找 int solve(int left,int right,const Point &p){ int mid=(left+right)>>1; if(left==right){ return isLeft(p,box[mid])==1? mid: -1; } if(isLeft(p,box[mid])==1){//在mid的左边 return solve(left,mid,p); }else{ return solve(mid+1,right,p); } } int main(){ int id; Point toy; while(1){ scanf("%d",&n); if(n==0)break; scanf("%d",&m); scanf("%lf %lf %lf %lf",&x1,&y1,&x2,&y2); add(x1,y1,x1,y2,0); add(x2,y1,x2,y2,n+1); double ui,li; for(int i=1;i<=n;i++){ scanf("%lf %lf",&ui,&li); add(ui,y1,li,y2,i);//盒子里添加隔板 } memset(bin,0,(n+1)*sizeof(int)); for(int i=0;i<m;i++){ scanf("%lf %lf",&toy.x,&toy.y); if(inside(toy)){//如果玩具确实扔到盒子里了,就计算玩具所在的格子 id=solve(1,n+1,toy); if(id>0)bin[id-1]++; else printf("ERROR!\n"); } } //print result for(int i=0;i<=n;i++){ printf("%d: %d\n",i,bin[i]); } printf("\n"); } return 0; }
相关文章推荐
- 计算几何算法基础————判断点是否在线段上(另附叉积的重要应用,折线段的拐向判断)
- POJ 1696 Space Ant 计算几何 叉积的应用
- pick定理的应用——简单的计算几何问题Triangle
- POJ2318---TOYS (基础计算几何:叉积应用)
- Pipe--计算几何叉积的应用
- 二分+叉积 apio2011 陈可卿 计算几何的一道简单题 poj2318 兼集训总结
- POJ2318 计算几何利用简单的叉积运算
- 计算几何之叉积(外积)得应用
- hrbustoj 1318:蛋疼的蚂蚁(计算几何,凸包变种,叉积应用)
- [您有新的未分配科技点]计算几何入门(1):点,向量以及向量的简单应用
- HDU1798 简单高中的计算几何题= =。正余弦定理的综合应用么。。。
- Java Web+GeoTools工具+自定义几何对象构造器+简单应用
- 计算几何基础——矢量和叉积
- (计算几何8.1.3.1)UVA 10213 How Many Pieces of Land?(使用欧拉公式的应用顶点数+面数-棱数 = 2)
- HDU 1154 Cutting a Polygon(基础计算几何知识综合应用)
- POJ 2398 Toy Storage(叉积的简单应用)
- HDU 4720 Naive and Silly Muggles (简单计算几何)
- POJ 2398 Toy Storage [叉积判断+二分查找]【计算几何】
- POJ 2405 Beavergnaw (计算几何-简单题)
- hdu-1154 Cutting a Polygon(计算几何综合应用,多模板)