POJ2318:二分+叉积

POJ2318

题解:

  • n个纸板把矩形分成(n+1)个区域,m个玩具随机仍在里面,求每个区域的玩具的个数,区域编号从0开始到n。
  • 二分查找点在哪个位置。如果点P在某条线段AB的左边(A在上面,B在下面),那么PA×PB<0。二分查找最近的线段的左边。

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
int const N = 5000 + 10;
int n,m,x1,y1,x2,y2;
int sum[N];
typedef struct Point{
	int x,y;
}Vector;
Vector up[N],down[N];
int cross(Vector a,Vector b){
	return a.x * b.y - a.y * b.x;
}
bool judge(int a,int b,int i){   
	Vector v1 = (Vector){up[i].x - a,up[i].y - b};
	Vector v2 = (Vector){down[i].x - a,down[i].y - b};
	return cross(v1,v2) < 0;
}
int solve(int a,int b){
	int l = 1,	r = n,	ans = n+1;
	while(l <= r){
		int mid = (l + r) >> 1;
		if(judge(a,b,mid)){    //如果(a,b)在线段mid的左边
			ans = mid;
			r = mid - 1;
		}else{
			l = mid + 1;
		}
	}
	return ans - 1;
}
int main(){
	while(~scanf("%d",&n) && n){
		scanf("%d%d%d%d%d",&m,&x1,&y1,&x2,&y2);
		memset(sum,0,sizeof(sum));
		for(int i=1;i<=n;i++){
			int a,b;
			scanf("%d%d",&a,&b);
			up[i] = (Point){a,y1};
			down[i] = (Point){b,y2};
		}
		for(int i=1;i<=m;i++){
			int a,b;
			scanf("%d%d",&a,&b);
			sum[solve(a,b)]++;
		}
		for(int i=0;i<=n;i++)
			printf("%d: %d\n",i,sum[i]);
		printf("\n");
	}
	return 0;
}

 

猜你喜欢

转载自blog.csdn.net/weixin_42264485/article/details/88879473