最远点对问题[转]
最远点对问题
接下来所谓旋转卡壳法(类似求数组中最长子段的和):
类似于“最近点对问题”,这个问题也可以用枚举的方法求解,时间复杂度O(n^2)。假设平面上有n个点,那么这一对最远点必然存在于这n个点所构成的一 个凸包上,为了降低时间复杂度,可以先将这n个点按极角排序,然后利用Graham_scan法求出这个凸包,再枚举凸包上的所有顶点(也可以用旋转卡 壳)求出这个最远距离,时间复杂度O(nlogn)。再最坏的情况下,如果这n个点本身就构成了一个凸包,时间复杂度为O(n^2)。该算法的平均复杂度 为O(nlogn)。
#include
<
cstdio
>
#include < cstring >
#include < cmath >
#include < cstdlib >
const int MAXN = 100001 ;
const double eps = 1e - 6 ;
struct point{
double x,y;
}p[MAXN],h[MAXN];
inline double distance( const point & p1, const point & p2){
return sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
}
inline double multiply( const point & sp, const point & ep, const point & op){
return ((sp.x - op.x) * (ep.y - op.y) - (ep.x - op.x) * (sp.y - op.y));
}
int cmp( const void * a, const void * b){
point * p1 = (point * )a;
point * p2 = (point * )b;
double t = (p1 -> y - p[ 0 ].y) * (p2 -> x - p[ 0 ].x) - (p2 -> y - p[ 0 ].y) * (p1 -> x - p[ 0 ].x);
if (t > eps) return 1 ;
else if (fabs(t) <= eps) return 0 ;
else return - 1 ;
}
void anglesort(point p[], int n){
int i,k = 0 ;
point temp;
for (i = 1 ;i < n;i ++ )
if (p[i].x < p[k].x || (p[i].x == p[k].x) && (p[i].y < p[k].y))
k = i;
temp = p[ 0 ],p[ 0 ] = p[k],p[k] = temp;
qsort(p + 1 ,n - 1 , sizeof (point),cmp);
}
void Graham_scan(point p[],point ch[], int n, int & len){
int i,top = 2 ;
anglesort(p,n);
if (n < 3 ){
for (i = 0 ,len = n;i < n;i ++ ) ch[i] = p[i];
return ;
}
ch[ 0 ] = p[ 0 ],ch[ 1 ] = p[ 1 ],ch[ 2 ] = p[ 2 ];
for (i = 3 ;i < n;i ++ ){
while (multiply(p[i],ch[top],ch[top - 1 ]) >= 0 ) top -- ;
ch[ ++ top] = p[i];
}
len = top + 1 ;
}
int main(){
int i,j,n,len;
double d,ans;
while (scanf( " %d " , & n),n){
for (i = 0 ;i < n;i ++ ) scanf( " %lf %lf " , & p[i].x, & p[i].y);
Graham_scan(p,h,n,len);
for (ans = i = 0 ;i < len;i ++ )
for (j = i + 1 ;j < len;j ++ ){
d = distance(h[i],h[j]);
if (d > ans) ans = d;
}
printf( " %.2lf\n " ,ans);
}
return 0 ;
}
#include < cstring >
#include < cmath >
#include < cstdlib >
const int MAXN = 100001 ;
const double eps = 1e - 6 ;
struct point{
double x,y;
}p[MAXN],h[MAXN];
inline double distance( const point & p1, const point & p2){
return sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
}
inline double multiply( const point & sp, const point & ep, const point & op){
return ((sp.x - op.x) * (ep.y - op.y) - (ep.x - op.x) * (sp.y - op.y));
}
int cmp( const void * a, const void * b){
point * p1 = (point * )a;
point * p2 = (point * )b;
double t = (p1 -> y - p[ 0 ].y) * (p2 -> x - p[ 0 ].x) - (p2 -> y - p[ 0 ].y) * (p1 -> x - p[ 0 ].x);
if (t > eps) return 1 ;
else if (fabs(t) <= eps) return 0 ;
else return - 1 ;
}
void anglesort(point p[], int n){
int i,k = 0 ;
point temp;
for (i = 1 ;i < n;i ++ )
if (p[i].x < p[k].x || (p[i].x == p[k].x) && (p[i].y < p[k].y))
k = i;
temp = p[ 0 ],p[ 0 ] = p[k],p[k] = temp;
qsort(p + 1 ,n - 1 , sizeof (point),cmp);
}
void Graham_scan(point p[],point ch[], int n, int & len){
int i,top = 2 ;
anglesort(p,n);
if (n < 3 ){
for (i = 0 ,len = n;i < n;i ++ ) ch[i] = p[i];
return ;
}
ch[ 0 ] = p[ 0 ],ch[ 1 ] = p[ 1 ],ch[ 2 ] = p[ 2 ];
for (i = 3 ;i < n;i ++ ){
while (multiply(p[i],ch[top],ch[top - 1 ]) >= 0 ) top -- ;
ch[ ++ top] = p[i];
}
len = top + 1 ;
}
int main(){
int i,j,n,len;
double d,ans;
while (scanf( " %d " , & n),n){
for (i = 0 ;i < n;i ++ ) scanf( " %lf %lf " , & p[i].x, & p[i].y);
Graham_scan(p,h,n,len);
for (ans = i = 0 ;i < len;i ++ )
for (j = i + 1 ;j < len;j ++ ){
d = distance(h[i],h[j]);
if (d > ans) ans = d;
}
printf( " %.2lf\n " ,ans);
}
return 0 ;
}
接下来所谓旋转卡壳法(类似求数组中最长子段的和):
int
main(){
while ( ~ scanf( " %d " , & n)) {
for ( int i = 0 ; i < n; i ++ )
p[i].read();
int top = 0 ;
tubao(p, id, n, top);
int area, area2, i, j, k, t, maxx = 0 ;
for (i = 0 , k = 2 ; i < top; i ++ ){
j = (i + 1 ) % top;
t = (k + 1 ) % top;
area = fabs(xmul(p[id[i]], p[id[k]], p[id[j]]));
area2 = fabs(xmul(p[id[i]], p[id[t]], p[id[j]]));
while (area < area2){
area = area2;
k = (k + 1 ) % top;
t = (k + 1 ) % top;
area2 = fabs(xmul(p[id[i]], p[id[t]], p[id[j]]));
maxx = max(maxx, max( dist(p[id[i]], p[id[k]]), dist(p[id[i]], p[id[t]]) ));
}
}
if (maxx != 0 )
printf( " %lf\n " , maxx);
else
printf( " %lf\n " , dist(p[id[ 0 ]], p[id[top - 1 ]]));
}
}
while ( ~ scanf( " %d " , & n)) {
for ( int i = 0 ; i < n; i ++ )
p[i].read();
int top = 0 ;
tubao(p, id, n, top);
int area, area2, i, j, k, t, maxx = 0 ;
for (i = 0 , k = 2 ; i < top; i ++ ){
j = (i + 1 ) % top;
t = (k + 1 ) % top;
area = fabs(xmul(p[id[i]], p[id[k]], p[id[j]]));
area2 = fabs(xmul(p[id[i]], p[id[t]], p[id[j]]));
while (area < area2){
area = area2;
k = (k + 1 ) % top;
t = (k + 1 ) % top;
area2 = fabs(xmul(p[id[i]], p[id[t]], p[id[j]]));
maxx = max(maxx, max( dist(p[id[i]], p[id[k]]), dist(p[id[i]], p[id[t]]) ));
}
}
if (maxx != 0 )
printf( " %lf\n " , maxx);
else
printf( " %lf\n " , dist(p[id[ 0 ]], p[id[top - 1 ]]));
}
}