POJ 2318 TOYS(向量基本运算)

本文介绍了一种算法,用于解决给定隔板和玩具坐标时,如何快速计算每个隔板区域内的玩具数量的问题。通过二分查找和向量叉乘的方法,实现了高效的玩具计数。

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

【题目大意】

    有一个矩阵的盒子,用隔板分割成很多块,如下图所示:

    

    每个隔板的两端分别在矩阵的上下边界上,且任两个隔板不会相交。现给定矩阵左上角和右下角的坐标,每个隔板两端点的坐标以及一些玩具的坐标,问每个小区域内分布有多少玩具?

    输入多个case,每个case第一行输入6个整数:n、m、x1、y1、x2、y2,n是隔板数,m是玩具个数,0<n≦5000,0<m≦5000,( x1 , y1 )、( x2 , y2 )分别是矩阵左上角和右下角坐标。接下来n行每行输入两个数U、L,代表第i个隔板的上下端点坐标分别是( Ui , y1 ),( Li , y2 )。隔板按照从左到右的顺序给出,并且任意两隔板不会相交。接下来m行给出玩具坐标,玩具不会恰好落在隔板上或边界上。单独输入一行0代表输入结束。

    输出每个小块中分布的玩具数目。

【输入样例】

 

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: 2
1: 1
2: 1
3: 1
4: 0
5: 1

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

    n个不相交的隔板将矩阵分割成n+1块;由于隔板是按从左到右的顺序给出,所以对于一个确定位置的玩具,可以通过二分计算其所在的块的编号,二分过程只需要找到第一个在其右侧的隔板即可。此处需判断点与线的位置关系,方法见https://blog.youkuaiyun.com/g21glf/article/details/80904435点击打开链接向量叉积一段。

    楼楼的代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define N 5010
struct point{
	int x,y;
	point(){}
	point(int _x,int _y):x(_x),y(_y){} 
	//定义两种构造函数 
	point operator-(const point a) const  //向量减法 
	{
		return point(x-a.x,y-a.y);
	}
	int operator*(const point a) const    //向量叉乘判断位置 
	{
		return x*a.y-y*a.x;
	}
};

int n,m,x1,y1,x2,y2;
int U[N],L[N];
int ans[N];                               //ans保存每个小区域有多少玩具,即解 

bool ch(int x,int y,int id)               //检验编号为id的隔板是否在点(x,y)左侧 
{
	point a=point(L[id],y2),b=point(U[id],y1);
	point c=point(x,y);
	return (c-a)*(b-a)>0;                 //此处直接用叉乘来判断点与直线的位置关系 
}

int find(int x,int y)                     //二分找到点(x,y)所在的区域的编号 
{
	int l=0,r=n+1,mid;
	while(l<r)
	{
		mid=(l+r)>>1;
		if(ch(x,y,mid))
		  l=mid+1;
		else
		  r=mid;
	}
	return l-1;                           //l是点(x,y)右侧第一个隔板,则(x,y)所在的块的编号为l-1 
}

int main()
{
	while(~scanf("%d",&n),n)
	{
		int i,j;
		memset(ans,0,sizeof(ans));        //注意每次都应初始化ans数组 
		scanf("%d%d%d%d%d",&m,&x1,&y1,&x2,&y2);
		U[0]=L[0]=x1,U[n+1]=L[n+1]=x2;
		for(i=1;i<=n;++i)
		  scanf("%d%d",&U[i],&L[i]);
		int x,y;
		for(i=0;i<m;++i)                  //依次输入每个玩具的坐标,并判断其所在区间 
		{
			scanf("%d%d",&x,&y); 
			ans[find(x,y)]++;             //find(x,y)查询点(x,y)所属的区间编号 
		}
		for(i=0;i<=n;++i)
		  printf("%d: %d\n",i,ans[i]);
		cout<<endl;
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值