【解题报告】 POJ 2318 TOYS -- 判断点在某个梯形内 叉积 + 二分

本博客介绍了如何解决POJ 2318问题,即计算长方体盒子中隔板划分的区域内的玩具数量。提供了两种解决方案,一种是将矩形区域转化为多个梯形并使用二分法,另一种是通过比较隔板位置更新区域玩具计数。并给出了具体的C语言实现代码,包括结构体定义、叉积计算以及二分查找等关键函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目连接: POJ 2318
题目大意:给一个长方体盒子,中间竖直插上若干隔板,将盒子分成了若干区域,现在往盒子里丢玩具,问最后各个区域内含有多少玩具。
这道题有两个思路:
             一个是,将矩形区域分割成多个梯形区域,然后对每一个点进行判断,在哪一个区域中。(二分快一些)
             一个是,将每个点与中间的隔板进行比较,如果在该隔板左边 则隔板左边的区域+1,在右边 则隔板右边的区域+1,输出的时候第一个区域不动,后面每个区域要减去前一个区域的点数再输出
// POJ 2318 TOYS -- 判断点在某个梯形内   叉积 + 二分
//
/*test data
1 1 0 10 60 0
3 1

40 10

5 6 0 10 60 0
3 1
4 3
6 8
10 10
15 30

1 5
2 1
2 8
5 5
40 10
7 9

4 10 0 10 100 0
20 20
40 40
60 60
80 80

 5 10
15 10
25 10
35 10
45 10
55 10
65 10
75 10
85 10
95 10
0
	==
	0: 0
	1: 1

	0: 2
	1: 1
	2: 1
	3: 1
	4: 0
	5: 1

	0: 2
	1: 2
	2: 2
	3: 2
	4: 2

*/

#include <stdio.h>
#include <math.h>
#include <string.h>

const double Pzero = 0.000001;
const int MAXP = 5005;

struct POINT {
	double x,y;
}toy[MAXP];
struct Square {
	POINT a,b,c,d;
}s[MAXP];
int squ[5010]; // every square


double Abs(double a){
	return (a>Pzero)?(a):(-a);
}

double XJ(POINT a,POINT b,POINT p){
	// vector a->b (b.x-a.x, b.y-a.y)
	// vector a->p (p.x-a.x, p.y-a.y)
	// calc a->b X a->p
	return ( (b.x-a.x)*(p.y-a.y) - (b.y-a.y)*(p.x-a.x) );
}

bool InSquare(POINT p,Square s){
	// vector (s.b , s.a) point p
	// vector (s.d , s.c) point p
	// vector (s.c , s.a) point p
	// vector (s.d , s.b) point p
	// 
	if ((XJ(s.b, s.a, p) * XJ(s.d, s.c, p) < Pzero) && (XJ(s.c, s.a, p) * XJ(s.d, s.b, p) < Pzero))
		return true;
	return false;
}


int binaryserach(Square* regin,	int begin, int end,	 POINT goal	){// 找到了返回数组中对应的下标,找不到返回-1
					//查找的范围 查找的开始  查找的结束 目标
	int mid = (begin + end) /2;
	if ( InSquare(goal, regin[mid]) )
		return mid;
	if (begin >= end) 
		return -1;

	if ( XJ(regin[mid].a, regin[mid].b, goal) < Pzero) // left
		return binaryserach(regin,begin,mid-1,goal);
	if ( XJ(regin[mid].c, regin[mid].d, goal) > Pzero) // right
		return binaryserach(regin,mid+1,end,goal);

}

void calculation(int m,int ns){
	for (int i=0;i<m;i++){
		scanf("%lf%lf",&toy[i].x,&toy[i].y);
		int j = binaryserach(s,0,ns,toy[i]);
		if (j!=-1)
			squ[j]++;
	}
}

void init(int n,int m,POINT up,POINT low){
	// from up to low
	double tempa,tempb;

	// left side
	s[0].a.x = up.x;
	s[0].a.y = up.y;
	s[0].b.x = up.x;
	s[0].b.y = low.y;
	for (int i = 0; i < n; i++){
		scanf("%lf%lf",&tempa,&tempb);
		s[i].c.x = tempa;
		s[i].c.y = up.y;
		s[i].d.x = tempb;
		s[i].d.y = low.y; 

		// next square
		s[i+1].a.x = s[i].c.x;
		s[i+1].a.y = s[i].c.y;
		s[i+1].b.x = s[i].d.x;
		s[i+1].b.y = s[i].d.y;
	}
	// right side
	s[n].c.x = low.x;
	s[n].c.y = up.y;
	s[n].d.x = low.x;
	s[n].d.y = low.y; 

	memset(squ, 0, sizeof(squ));
}

void PrintAns(int ns){
	for (int i=0;i<ns;i++){
		printf("%d: %d\n",i,squ[i]);
	}
	printf("\n");
}

int main()
{
//	freopen("in.txt","r",stdin);
	int n,m;
	POINT up,low;
	while(scanf("%d%d%lf%lf%lf%lf",&n,&m,&up.x,&up.y,&low.x,&low.y),n){
		init(n,m,up,low);
		calculation(m,n+1);
		PrintAns(n+1);
	}

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值