POJ2318-toys(计算几何基础+二分)

来源:互联网 发布:2017广西广电网络套餐 编辑:程序博客网 时间:2024/05/03 08:15

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

题目大意:给定一个矩形和一些线段,线段将矩形分割为从左至右的若干部分,之后给出一些玩具的坐标,求每个部分中玩具的数量

题解:

计算几何水题……

注意到题目给出线段是按从左至右的顺序给出的,考虑到对于每条直线,玩具只存在两种状态:在它左边或者在它右边,并且这种状态是单调的(一定存在一个分界,它左边的线段都在玩具右边,它右边的线段都在玩具左边)

于是考虑二分答案

然后根据叉积判断点和线段的关系(可以将点减去线段的起点,和原线段组成两个同起点的向量,然后根据叉积的性质:若 P X Q > 0,则向量Q在向量P的逆时针方向,若P X Q < 0,则向量Q在向量P的顺时针方向,若P X Q = 0,则向量Q和向量P同向或反向,但这题保证玩具不落在分界线,因此不用考虑)

注意有多组数组,要做好初始化操作

效率:O(mlogn)(有m个玩具,对于每个玩具,二分O(logn)+判断O(1))

代码如下:

#include<iostream>#include<cstdio>#include<cstdlib>#include<string>#include<cstring>#include<cmath>#include<algorithm>const double eps=1e-10;using namespace std;struct point{double x,y;point(double x=0,double y=0):x(x),y(y){}};typedef point vector;vector operator +(vector a,vector b){return vector(a.x+b.x,a.y+b.y);}vector operator -(point a,point b){return vector(a.x-b.x,a.y-b.y);}vector operator *(vector a,double p){return vector(a.x*p,a.y*p);}vector operator /(vector a,double p){return vector(a.x/p,a.y/p);}int dcmp(double x){if(x<0) x=-x;if(x<eps) return 1;return 0;}bool operator ==(const point& a,const point& b){return dcmp(a.x-b.x)&&dcmp(a.y-b.y);}double dot(vector a,vector b){return a.x*b.x+a.y*b.y;}double cross(vector a,vector b){return a.x*b.y-a.y*b.x;}int n,m,x_1,x_2,y_1,y_2,u[5010],l[5010],ans[5010],tx,ty;void cr(){for(int i=0;i<=n;i++) u[i]=l[i]=ans[i]=0;}bool check(int line){vector lin=vector(u[line]-l[line],y_1-y_2);vector tlin=vector(tx-l[line],ty-y_2);if(cross(lin,tlin)>-eps) return 0;return 1;}int main(){int L,R,mid;bool flag=0;for(scanf("%d",&n);n;cr(),scanf("%d",&n)){if(flag) printf("\n");scanf("%d%d%d%d%d",&m,&x_1,&y_1,&x_2,&y_2);for(int i=1;i<=n;i++) scanf("%d%d",&u[i],&l[i]);for(int i=1;i<=m;i++){   scanf("%d%d",&tx,&ty);   L=1;R=n;   while(L!=R)   { mid=(L+R)>>1; if(check(mid)) L=mid+1; else R=mid;   }   if(L==n){if(check(n)) ans[n]++;else ans[n-1]++;}   else ans[L-1]++;}for(int i=0;i<=n;i++){printf("%d: %d\n",i,ans[i]);}flag=1;}return 0;    }

代码不长,就是写得比较丑QAQ将就着看吧QAQ

0 0
原创粉丝点击