题目大意:
现只有一个测例,测例中给出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, 方格的,平方的