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

版权声明:本文为博主原创文章,转载请联系博主(通常都会同意就是了) https://blog.csdn.net/cccccwb/article/details/50731738

题目: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

猜你喜欢

转载自blog.csdn.net/cccccwb/article/details/50731738