POJ 2318 TOYS

题目大意:

        有一个矩形盒子里面有n块斜的挡板(1 ≤ n ≤ 5,000),矩形盒子左上角坐标为(x1, y1),右下角坐标为(x2, y2),接着会给出每个挡板的信息(Ui, Li),表示挡板的上端点为(Ui, y1),下端点为(Li, y2),其中保证各个挡板不相交,并且挡板信息按照从左往右的顺序依次给出,接下来给出m个点的坐标(1 ≤ m ≤ 5,000)(xi, yi),输入保证点不会落在挡板上,但是可能后落在矩形边框上,但绝不会落在矩形外。

        现有多个测例,每个测例都会给出上述信息,输入以n = 0结束,对于每个测例,要求从左到右输出每个隔间中点的个数,形式为"i: n",表示第i个隔间中有n个点,每个隔间占一行,隔间编号从0 ~ n共n + 1个,每个测例之间的输出用空格隔开。

题目链接

注释代码:

/*                                        
 * Problem ID : POJ 2318 TOYS
 * Author     : Lirx.t.Una                                        
 * Language   : C++                            
 * Run Time   : 235 ms                                        
 * Run Memory : 292 KB                                        
*/

#include <iostream>
#include <cstring>
#include <cstdio>

//挡板的最大数量
#define	MAXN	5000

using namespace std;

//矩形的左上角坐标以及右下角坐标
int		x1, x2;
int		y1, y2;

struct	Point {//表示点
	//可以用来记录挡板信息
	//也可以用来记录普通点的信息
	
	//如果是挡板信息则x, y表示Ui和Li
	int		x, y;
	
	Point(void) {}
	Point(int xx, int yy) : x(xx), y(yy) {}
	
	friend istream &
	operator>>(istream &is, Point &p) {
		
		is >> p.x >> p.y;
		return is;
	}
	
	int
	operator*(Point &p2) {//计算叉积
		//左操作数为点,右操作数为挡板
		//设点为p0,挡板上端点为p1,下端点为p2
		
		Point	pp1(p2.y - x, y2 - y);//得到向量p0->p2
		Point	pp2(p2.x - p2.y, y1 - y2);//得到向量p2->p1
		
		return pp1.x * pp2.y - pp1.y * pp2.x;//计算向量pp1×pp2
		//如果>0表示点在挡板左边否则就在挡板右边(因为后面的二分保证了叉积不是大于0就是小于0
		//不可能等于0)
	}
};

Point	p[MAXN + 2];//n + 2块挡板,矩形左边和右边也算两个,但是不用记录因为二分查找用不到
int		cnt[MAXN + 1];//记录每个隔间中点的个数
int		n, m;//挡板数和点数

int
bsrch(Point &_p) {//二分查找_p点落在哪个隔间中
	
	int		lft, rht, mid;
	
	lft = 0;
	rht = n + 1;
	
	while ( lft + 1 < rht ) {//规定左右最小间距为1,这样就永远都不会查到矩形左右两边了
		//也就避免了检验叉积为0的特殊情况了
		
		mid = ( lft + rht ) >> 1;
		
		if  ( _p * p[mid] > 0 ) rht = mid;//在mid左边
		else lft = mid;//右边
	}
	
	return lft;//隔间号和左挡板一致
}

int
main() {
	
	int		i;
	
	Point	_p;//点
	
	while ( scanf("%d", &n), n ) {
		
		memset(cnt, 0, sizeof(cnt));
		
		scanf("%d%d%d%d%d", &m, &x1, &y1, &x2, &y2);		
		for ( i = 1; i <= n; i++ ) cin >> p[i];
		
		while ( m-- ) {
			
			cin >> _p;
			cnt[ bsrch(_p) ]++;
		}
		
		for ( i = 0; i <= n; i++ )
			printf("%d: %d\n", i, cnt[i]);
		putchar('\n');
	}
	
	return 0;
}
无注释代码:

#include <iostream>
#include <cstring>
#include <cstdio>

#define	MAXN	5000

using namespace std;

int		x1, x2;
int		y1, y2;

struct	Point {

	int		x, y;

	Point(void) {}
	Point(int xx, int yy) : x(xx), y(yy) {}

	friend istream &
	operator>>(istream &is, Point &p) {
	
		is >> p.x >> p.y;
		return is;
	}

	int
	operator*(Point &p2) {
	
		Point	pp1(p2.y - x, y2 - y);
		Point	pp2(p2.x - p2.y, y1 - y2);

		return pp1.x * pp2.y - pp1.y * pp2.x;
	}
};

Point	p[MAXN + 2];
int		cnt[MAXN + 1];
int		n, m;

int
bsrch(Point &_p) {

	int		lft, rht, mid;

	lft = 0;
	rht = n + 1;

	while ( lft + 1 < rht ) {
	
		mid = ( lft + rht ) >> 1;

		if  ( _p * p[mid] > 0 ) rht = mid;
		else lft = mid;
	}

	return lft;
}

int
main() {

	int		i;

	Point	_p;

	while ( scanf("%d", &n), n ) {
	
		memset(cnt, 0, sizeof(cnt));

		scanf("%d%d%d%d%d", &m, &x1, &y1, &x2, &y2);
		for ( i = 1; i <= n; i++ ) cin >> p[i];

		while ( m-- ) {
		
			cin >> _p;
			cnt[ bsrch(_p) ]++;
		}

		for ( i = 0; i <= n; i++ )
			printf("%d: %d\n", i, cnt[i]);
		putchar('\n');
	}

	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值