题目大意:
现空头N个特工到敌方阵营去破坏其发电站,现有N个特工和N个发电站(1 ≤ N ≤ 100,000),由于地方空军阻拦等原因特工没有按照预定地点降落,因此降落地点非常散乱,现需要你计算力发电站最近的一个特工以及这个最近距离。
现有多个测例(测例数题中给出),每个测例中都给出N,接着会给出N个发电站的二维坐标和N个特工的坐标,所有坐标的范围为[0, 1000000000],所有的输入都是int型的,对于每个测例求出最近两点之间的距离(这两点分别是发电站和特工,不能是相同的东西),要求结果精确到小数点后3位,有可能有特工刚好降落到某个发电站的情况,这时最短距离就是0。
注释代码:
/*
* Problem ID : POJ 3714 Raid
* Author : Lirx.t.Una
* Language : C++
* Run Time : 2844 ms
* Run Memory : 4956 KB
*/
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
#define EPS 1E-9
#define INF 1E50
#define STATION true
#define AGENT false
//最大点数
//由于station和agent具有同样的最大数量
//因此为它们最大数量的两倍
#define MAXPOINTN 200000
//在求最近点对的合并一部中需要确定一个
//最小的边界合并区域
//YN即为该区域(只考虑水平范围)的最大点数
//只有要对该区域中的点按照y升序排列
#define YN 190
#define POW(x) ( (x) * (x) )
using namespace std;
struct Point {
double x, y;
bool type;//表示是station还是agent
friend istream &//输入
operator>>( istream &is, Point &p ) {
is >> p.x >> p.y;
return is;
}
double
operator^(Point &oth) {//求两点之间的欧式距离
if ( type != oth.type )
return sqrt( POW( x - oth.x ) + POW( y - oth.y ) );
else//如果是两个相同类型的点则不可达,因此距离为无穷大
return INF;
}
};
Point pt[MAXPOINTN];//点
int ys[YN];//y-sort,保存边界区域中的点的序号,之后要按照y升序排列
bool
xfcmp(const Point &p1, const Point &p2) {//对所有点按照x升序排列
//以求得x的中位数可以进行二分分治
//使该中垂线两边的点的数量相等或相差1
return p1.x < p2.x;
}
bool
yfcmp(int i, int j) {//对边界区域中的点进行y排序
return pt[i].y < pt[j].y;
}
double
nirst( int lft, int rht ) {//Nearest pair
//分治递归求最近点对之间的距离
if ( 1 == rht - lft )//只有两个点
return pt[lft] ^ pt[rht];
int mid;
if ( 2 == rht - lft ) {//只有三个点
mid = lft + 1;
return min( min( pt[lft] ^ pt[mid], pt[mid] ^ pt[rht] ),
pt[lft] ^ pt[rht] );
}
double mdist;//minimum distance,当前的最近点对距离,会不断覆盖
mid = ( lft + rht ) >> 1;//求中垂线,即x的中位数,之前已经把pt按照x升序排列了
mdist = min( nirst( lft, mid ), nirst( mid + 1, rht ) );//分治求两边的最近点对
if ( fabs(mdist) < EPS )//表示有重合station和agent,可以直接输出0.0的距离
return 0.0;
//接下来就是求两边交界的边界合并区中的最近点对了
//边界区域是中垂线两侧宽度为mdist的区域(总宽度为2mdist)
int ym;//区域中点的数量
int i, j;//计数变量
//向两边纵深,只找出里中垂线mdist以内的点即可
for ( ym = 0, i = mid; pt[mid].x - pt[i].x < mdist && i >= lft; i-- )
ys[ym++] = i;
for ( i = mid + 1; pt[i].x - pt[mid + 1].x < mdist && i <= rht; i++ )
ys[ym++] = i;
sort(ys, ys + ym, yfcmp);//对区域中的点按照y升序排列
//由于在 2mdist × mdist的区域中最多只有8个点,因此在边界区域中
//最多只有 8 × ( ( ymax - ymin ) / mdist )个点
//因此点数还是比较少的,因此可以枚举两两之间的距离
for ( i = 0; i < ym; i++ )
for ( j = i + 1;
//剪枝!!!利用不等式放缩剪枝,如果y之差都大于mdist了
//则两点之间距离肯定大于mdist(直角三角形斜边大于直角边)
j < ym && pt[ ys[j] ].y - pt[ ys[i] ].y < mdist;
j++ )
mdist = min( mdist, pt[ ys[i] ] ^ pt[ ys[j] ] );
return mdist;
}
int
main() {
int t;//测例数
int n;//station和agent的数量
int nn;//前两者的综合
int i;//技术变量
scanf("%d", &t);
while ( t-- ) {
scanf("%d", &n);
nn = n << 1;//nn = 2n
for ( i = 0; i < n; i++ ) {
cin >> pt[i];
pt[i].type = STATION;
}
for ( i = n; i < nn; i++ ) {
cin >> pt[i];
pt[i].type = AGENT;
}
sort(pt, pt + nn, xfcmp);
printf("%.3lf\n", nirst( 0, nn - 1 ));
}
return 0;
}
无注释代码:
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
#define EPS 1E-9
#define INF 1E50
#define STATION true
#define AGENT false
#define MAXPOINTN 200000
#define YN 190
#define POW(x) ( (x) * (x) )
using namespace std;
struct Point {
double x, y;
bool type;
friend istream &
operator>>( istream &is, Point &p ) {
is >> p.x >> p.y;
return is;
}
double
operator^(Point &oth) {
if ( type != oth.type )
return sqrt( POW( x - oth.x ) + POW( y - oth.y ) );
else
return INF;
}
};
Point pt[MAXPOINTN];
int ys[YN];
bool
xfcmp(const Point &p1, const Point &p2) {
return p1.x < p2.x;
}
bool
yfcmp(int i, int j) {
return pt[i].y < pt[j].y;
}
double
nirst( int lft, int rht ) {
if ( 1 == rht - lft )
return pt[lft] ^ pt[rht];
int mid;
if ( 2 == rht - lft ) {
mid = lft + 1;
return min( min( pt[lft] ^ pt[mid], pt[mid] ^ pt[rht] ),
pt[lft] ^ pt[rht] );
}
double mdist;
mid = ( lft + rht ) >> 1;
mdist = min( nirst( lft, mid ), nirst( mid + 1, rht ) );
if ( fabs(mdist) < EPS )
return 0.0;
int ym;
int i, j;
for ( ym = 0, i = mid; pt[mid].x - pt[i].x < mdist && i >= lft; i-- )
ys[ym++] = i;
for ( i = mid + 1; pt[i].x - pt[mid + 1].x < mdist && i <= rht; i++ )
ys[ym++] = i;
sort(ys, ys + ym, yfcmp);
for ( i = 0; i < ym; i++ )
for ( j = i + 1;
j < ym && pt[ ys[j] ].y - pt[ ys[i] ].y < mdist;
<span style="white-space:pre"> </span> j++ )
<span style="white-space:pre"> </span>mdist = min( mdist, pt[ ys[i] ] ^ pt[ ys[j] ] );
return mdist;
}
int
main() {
int t;
int n;
int nn;
int i;
scanf("%d", &t);
while ( t-- ) {
scanf("%d", &n);
nn = n << 1;
for ( i = 0; i < n; i++ ) {
cin >> pt[i];
pt[i].type = STATION;
}
for ( i = n; i < nn; i++ ) {
cin >> pt[i];
pt[i].type = AGENT;
}
sort(pt, pt + nn, xfcmp);
printf("%.3lf\n", nirst( 0, nn - 1 ));
}
return 0;
}
单词解释:
raid:n, 突袭
retreat:vt, 撤退
stronghold:n, 要塞,大本营
repel:vt, 击退
sleepless:adj, 失眠的,不眠的
Arthur:人名,亚瑟
General:n, 将军,上将
nuclear:adj, 原子能的
disable:vt, 使残废
agent:n, 特工,代理人
paradrop:vt, 空投,伞投