算法导论-分治法-最近点对-HDOJ1007

原创 2014年03月20日 10:38:51

HDOJ1007的原题目是求出在不同时套中两个玩具的前提下,圆圈的最大半径。问题翻译过来就是求解最近点对的问题,这个问题是经典的分治法问题。

参考博客:http://www.cnblogs.com/peng-come-on/archive/2012/01/18/2325163.html

毫无疑问,通过暴力手段列举所有的点对并计算这些点对的距离,找出最小的一组,可以得到最后的结果。但是,这道题的数据规模非常大,所以,这种传统的方法肯定行不通。我试过,hdoj是超时的。

我对原博客的第3步和第4步有不同的看法。

原博客步骤:

1.读取数据,并将点按横坐标升序排列。
2.以最中间的那个点为基准,将平面内的点分为左右两个部分。递归调用mindis(int,int)函数,分别求出左右两个部分的点集的最短距离,并取两者中的较小值,即为min.
3.显然,min并不一定是最短距离,因为还可能存在一种情况,即点对中的一个点位于左区域,另一个点位于右区域。所以,我们取点集中横坐标与分界线的距离小于min的点,存入p2[N]数组中。
4.对p2[N]数组中的点按纵坐标进行排序,计算p2[N]数组中的点对的距离,如果存在小于min 的情况,就取代min作为最近距离。
最后,min即为平面内点集的最近距离。

我的步骤是:

1.读取数据,并将点按横坐标升序排列。
2.以最中间的那个点为基准,将平面内的点分为左右两个部分。递归调用mindis(int,int)函数,分别求出左右两个部分的点集的最短距离,并取两者中的较小值,即为min.
3.显然,min并不一定是最短距离,因为还可能存在一种情况,即点对中的一个点位于左区域,另一个点位于右区域。所以,我们取点集中横坐标与分界线的距离小于min的点,根据在分界线的左右,分别存入pxSmall[N]数组和pxLarge[N]数组中。

4.因为唯一可能的情况是一个点在pxSmall[N],另一个点在pxLarge[N]中。只要遍历这个两个数组便可以了。

下面是在原博客代码上的修改:

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

using namespace std;

#define N 1000010

struct point 
{
 double x;
 double y;
}p1[N],pxSmall[N],pxLarge[N];

double dis ( point a , point b )
{
	return sqrt( pow (a.x-b.x,2) + pow ( a.y-b.y,2 ) );
}

double min ( double a , double b )
{
	return a<b?a:b;
}

bool cpx ( point a , point b )
{
	return a.x < b.x ;
}
bool cpy ( point a , point b )
{
	return a.y < b.y ;
}

double mindis (int l, int r)
{
	if( l + 1 == r )
		return dis ( p1[l] ,p1[r] );
	if( l + 2 == r )
		return min ( dis ( p1[l] , p1[l+1] ) , min ( dis ( p1[l+1] , p1[r] ) , dis ( p1[l] , p1[r] ) ) );
	else
	{
		int mid ,count1=0, count2=0;
		double mini;
		mid = ( l + r) >> 1 ;
		mini = min ( mindis ( l , mid ) , mindis ( mid+1 , r ) );
		for( int i = l ; i <= r ; i++ )
		{
			if ( fabs ( p1[i].x - p1[mid].x ) <= mini )
			{
				if (p1[i].x-p1[mid].x < 0)
					pxSmall[count1++]=p1[i];
				else
					pxLarge[count2++]=p1[i];
			}
				
		}
		//直接遍历两个数组
		for(int i=0;i<count1;i++)
		{
			for(int j=0;j<count2;j++)
			{
				double temp = dis(pxSmall[i], pxLarge[j]); 
				if(temp<mini)
					mini=temp;
			}
		}
		/*
		sort ( p2 , p2+count , cpy );
		for ( int i=0 ; i < count ; i++ )
		{
			for ( int j = i+1; j < count ;j++)
			{
				if ( p2[j].y-p2[i].y>=mini)
					break;
				else if(dis (p2[j],p2[i])<mini)
					mini=dis(p2[j],p2[i]);
			}
		}
		*/
		return mini;
	}
}
  
  

int main()
{
 //freopen("input.txt","r",stdin);
	int n ;
	double dia ;
	while(scanf("%d",&n)==1&&n)
	{
		for(int i=0;i<n;i++)
		scanf("%lf%lf",&p1[i].x,&p1[i].y);
		sort ( p1 , p1 + n-1 , cpx );
		dia = mindis ( 0 , n-1 );
		printf("%.2f\n", dia / 2 );
	}
	return 0;
}

我在HDOJ上分别跑这两组代码,发现原博客runtime为1875ms,我的代码runtime为1093ms,比原博客的运行时间少了很多。因为少了排序这个步骤。当然,可能不同的数据集得到的运行时间不同,如果换一个数据集或数据集规模很大的时候原博客的方法可能更有优势。但是有一点,我的方法更好地符合分治法的要求,正确性是可以保证的。最近一直在学习《算法导论》,这本书真是神书,是算法中的算法,不仅仅告诉你算法,还会告诉你算法的证明。以后如果遇到分治法的问题,我会继续补充到这篇博客。

补充:参考博客:http://blog.csdn.net/junerfsoft/article/details/2975495

博客中提到了飞机调度的问题,说的很好。可惜因为每个点的坐标类型都是double类型的,不能直接找到那6个点,可以使用二分查找,但是也不是特别方便。我随便写了代码,时间上反而更长了。

计算几何 平面最近点对 nlogn分治算法 求平面中距离最近的两点

平面最近点对,指平面中距离最近的两点。本文详细介绍求解平面最近点对的nlogn分治算法。...
  • Lytning
  • Lytning
  • 2014年05月09日 10:16
  • 6784

最近点对问题

转自:http://blog.csdn.net/lonelycatcher/article/details/7973046       在二维平面上的n个点中,如何快速的找出最近的一对点,就是...
  • acm_1361677193
  • acm_1361677193
  • 2015年08月19日 19:52
  • 1278

最近点对问题

在二维平面上的n个点中,如何快速的找出最近的一对点,就是最近点对问题。     一种简单的想法是暴力枚举每两个点,记录最小距离,显然,时间复杂度为O(n^2)。     在这里介绍一种时间复杂度为...
  • lonelycatcher
  • lonelycatcher
  • 2012年09月12日 22:52
  • 21705

平面最近点对问题详解

算法:     0:把所有的点按照横坐标排序    1:用一条竖直的线L将所有的点分成两等份    2:递归算出左半部分的最近两点距离d1,右半部分的最近两点距离d2,取d=min(d1,d2)   ...
  • zhulei19931019
  • zhulei19931019
  • 2013年07月18日 00:30
  • 3407

0007算法笔记——【分治法】最接近点对问题

问题场景:在应用中,常用诸如点、圆等简单的几何对象代表现实世界中的实体。在涉及这些几何对象的问题中,常需要了解其邻域中其他几何对象的信息。例如,在空中交通控制问题中,若将飞机作为空间中移动的一个点来看...
  • liufeng_king
  • liufeng_king
  • 2013年01月09日 22:09
  • 37620

找最近点对问题-分治算法的应用

     分治算法的基本思想是:    分(divide):递归求解子问题,即:分解+求解,将问题分解为k个方便求解的小问题。    为什么说是递归求解呢,这里可以看作将一个问题分2个子问题,如果2个...
  • midgard
  • midgard
  • 2009年05月18日 19:13
  • 14963

求最近点对算法分析

问题描述:     在应用中,常用诸如点、圆等简单的几何对象代表现实世界中的实体。在涉及这些几何对象的问题中,常需要了解其邻域中其他几何对象的信息。例如,在空中交通控制问题中,若将飞机作为空间中移动的...
  • lishuhuakai
  • lishuhuakai
  • 2013年06月20日 09:53
  • 8959

求最近点对算法分析

本文引自  http://blog.csdn.net/lishuhuakai/article/details/9133961 问题描述:     在应用中,常用诸如点、圆等简单...
  • zyh15
  • zyh15
  • 2015年10月11日 19:39
  • 1187

分治算法求最近点对

http://acm.hdu.edu.cn/showproblem.php?pid=1007          先说下题意,很简单,给n个点的坐标,求距离最近的一对点之间距离的一半。第一行是一个...
  • Hackbuteer1
  • Hackbuteer1
  • 2012年04月20日 17:19
  • 22617

hdu 1007最近点对

先说下题意,很简单,给n个点的坐标,求距离最近的一对点之间距离的一半。第一行是一个数n表示有n个点,接下来n行是n个点的x坐标和y坐标,实数。      这个题目其实就是求最近点对的距离。主要思...
  • hellobabygogo3
  • hellobabygogo3
  • 2012年10月06日 10:05
  • 7620
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:算法导论-分治法-最近点对-HDOJ1007
举报原因:
原因补充:

(最多只允许输入30个字)