POJ 2187 Beauty Contest

题目大意:

        现只有一个测例,测例中给出N个点(2 ≤ N ≤ 50,000),以及N个点的坐标,范围为[-10000, 10000],现要求最远两点之间的距离的平方。

题目链接

注释代码:

/*        
 * Problem ID : POJ 3714 Raid 
 * Author     : Lirx.t.Una        
 * Language   : C++       
 * Run Time   : 391 ms        
 * Run Memory : 644 KB        
*/ 

#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>

//maximum number of farms
//农场的最大数量
#define	MAXFARMN		50000

#define	POW(x)		( (x) * (x) )

using namespace std;

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;
	}

	Point
	operator-(const Point &oth)
	const {
	
		return Point( x - oth.x, y - oth.y );
	}

	int
	operator*(Point oth) {
	
		return x * oth.y - oth.x * y;
	}

	bool
	operator<(Point &p) {
	
		return y < p.y || ( y == p.y && x < p.x );
	}

	bool
	operator>=(Point &p) {
	
		return abs(x) >= abs(p.x) && abs(y) >= abs(p.y);
	}

	int
	operator^(Point &p) {//计算两点距离的平方
	
		return POW( x - p.x ) + POW( y - p.y );
	}
};

Point	pt[MAXFARMN];
Point	stk[MAXFARMN];

void
swp( int i, int j ) {

	Point	p;

	p	  = pt[i];
	pt[i] = pt[j];
	pt[j] = p;
}

bool
fcmp(const Point &p1, const Point &p2) {

	return ( p1 - *pt ) * ( p2 - *pt ) > 0;
}

int
graham(int n) {//计算凸包
	//并返回凸包的点数 + 1,即top的值(栈顶指针)

	int		i, j;
	int		mi;

	int		top;

	Point	pi, pj;

	for ( mi = 0, i = 1; i < n; i++ )
		if ( pt[i] < pt[mi] )
			mi = i;
	swp( 0, mi );
	sort(pt + 1, pt + n, fcmp);
	for ( j = 1, i = 2; i < n; i++ ) {

		if ( !( ( pi = pt[i] - *pt ) * ( pj = pt[j] - *pt ) ) ) {
		
			if ( pi >= pj ) pt[j] = pt[i];
			continue;
		}

		pt[++j] = pt[i];
	}
	n = j + 1;

	stk[0] = pt[0];
	stk[1] = pt[1];
	stk[2] = pt[2];

	top = 2;

	for (i = 3; i < n; i++ ) {
	
		while ( ( pt[i] - stk[top - 1] ) * ( stk[top] - stk[top - 1] ) >= 0 )
			top--;

		stk[++top] = pt[i];
	}

	return top;
}

int
rot_cliper(int n) {//rotating caliper
	//旋转卡壳计算最远点
	//最远点对一定属于凸包的对踵点对集
	//利用该方法不停逐步前进扫描临近对踵点得出最终答案

	int		d2;//distance^2,距离的平方,存放当前最短对踵点对距离平方
	int		hp;//heel point,对踵点

	int		i;//计数变量

	Point	p;//临时点

	//寻找i和i + 1的临近对踵点的方法:
	//从上一个对踵点(i - 1、i的临近对踵点)开始
	  //找( stk[i + 1] - stk[i] ) * ( stk[hp] - stk[i] )递增序列,当hp时峰顶,hp + 1开始持平或者下降时
	  //则hp是i的第一个对踵点,hp + 1是i的第二个对踵点,而hp + 1是i + 1的第一个对踵点而hp + 1不是i的对踵点
	//如此递推下去,当前点和下一点的第一对踵点在当前轮中计算,下一轮中递推地计算了下一点的第二对踵点
	//如此一来仿佛第一个的点(即0号)的第二对踵点没有计算,而实际上扫描是沿着凸包一周进行的,因此在扫描
	  //途中,某一点在计算其对踵点时刚好匹配了0号点,而在这样的点中必然会存在0号点的第二对踵点

	//注意在计算下一对踵点是使用模除( hp + 1 ) % ( n + 1 ),可能会产生循环,即n号点的下一个点是0号点
	  //而不存在n + 1号点!!!
	d2 = 0;
	for ( hp = 1, i = 0; i < n; i++ ) {

		p = stk[i + 1] - stk[i];
		while ( ( p * ( stk[ ( hp + 1 ) % ( n + 1 ) ] - stk[i] ) ) > ( p * ( stk[hp] - stk[i] ) ) )
			hp = ( hp + 1 ) % ( n + 1 );//当hp为n - 1时

		d2 = max( d2, max( stk[hp] ^ stk[i], stk[ ( hp + 1 ) % ( n + 1 ) ] ^ stk[i + 1] ) );
	}

	return d2;
}

int
main() {

	int		n;//点数
	int		i;//计数变量

	scanf("%d", &n);
	for ( i = 0; i < n; i++ )
		cin >> pt[i];

	//考虑两种特殊情况
	if ( 2 == n ) {

		printf("%d\n", pt[0] ^ pt[1]);
		return 0;
	}

	if ( 3 == n ) {
	
		printf("%d\n", max( pt[0] ^ pt[1], max( pt[0] ^ pt[2], pt[1] ^ pt[2] ) ));
		return 0;
	}

	printf("%d\n", rot_cliper( graham(n) ));

	return 0;
}

无注释代码:

#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>

#define	MAXFARMN		50000

#define	POW(x)		( (x) * (x) )

using namespace std;

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;
	}

	Point
	operator-(const Point &oth)
	const {
	
		return Point( x - oth.x, y - oth.y );
	}

	int
	operator*(Point oth) {
	
		return x * oth.y - oth.x * y;
	}

	bool
	operator<(Point &p) {
	
		return y < p.y || ( y == p.y && x < p.x );
	}

	bool
	operator>=(Point &p) {
	
		return abs(x) >= abs(p.x) && abs(y) >= abs(p.y);
	}

	int
	operator^(Point &p) {
	
		return POW( x - p.x ) + POW( y - p.y );
	}
};

Point	pt[MAXFARMN];
Point	stk[MAXFARMN];

void
swp( int i, int j ) {

	Point	p;

	p	  = pt[i];
	pt[i] = pt[j];
	pt[j] = p;
}

bool
fcmp(const Point &p1, const Point &p2) {

	return ( p1 - *pt ) * ( p2 - *pt ) > 0;
}

int
graham(int n) {

	int		i, j;
	int		mi;

	int		top;

	Point	pi, pj;

	for ( mi = 0, i = 1; i < n; i++ )
		if ( pt[i] < pt[mi] )
			mi = i;
	swp( 0, mi );
	sort(pt + 1, pt + n, fcmp);
	for ( j = 1, i = 2; i < n; i++ ) {

		if ( !( ( pi = pt[i] - *pt ) * ( pj = pt[j] - *pt ) ) ) {
		
			if ( pi >= pj ) pt[j] = pt[i];
			continue;
		}

		pt[++j] = pt[i];
	}
	n = j + 1;

	stk[0] = pt[0];
	stk[1] = pt[1];
	stk[2] = pt[2];

	top = 2;

	for (i = 3; i < n; i++ ) {
	
		while ( ( pt[i] - stk[top - 1] ) * ( stk[top] - stk[top - 1] ) >= 0 )
			top--;

		stk[++top] = pt[i];
	}

	return top;
}

int
rot_cliper(int n) {

	int		d2;
	int		hp;

	int		i;

	Point	p;

	d2 = 0;
	for ( hp = 1, i = 0; i < n; i++ ) {

		p = stk[i + 1] - stk[i];
		while ( ( p * ( stk[ ( hp + 1 ) % ( n + 1 ) ] - stk[i] ) ) > ( p * ( stk[hp] - stk[i] ) ) )
			hp = ( hp + 1 ) % ( n + 1 );

		d2 = max( d2, max( stk[hp] ^ stk[i], stk[ ( hp + 1 ) % ( n + 1 ) ] ^ stk[i + 1] ) );
	}

	return d2;
}

int
main() {

	int		n;
	int		i;

	scanf("%d", &n);
	for ( i = 0; i < n; i++ )
		cin >> pt[i];

	if ( 2 == n ) {

		printf("%d\n", pt[0] ^ pt[1]);
		return 0;
	}

	if ( 3 == n ) {
	
		printf("%d\n", max( pt[0] ^ pt[1], max( pt[0] ^ pt[2], pt[1] ^ pt[2] ) ));
		return 0;
	}

	printf("%d\n", rot_cliper( graham(n) ));

	return 0;
}

单词解释:

goodwill:n, 友好

simplicity:n, 简易,朴素

suitcase:n, 手提箱,衣箱

hay:n, 干草

refill:vt, 再装满

squared:adj, 方格的,平方的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值