最近&最远点对

本文介绍了一种计算二维平面上最近点对和最远点对的方法,利用Gram_Scan算法进行凸包处理,并通过二分搜索找到最近点对,最后遍历凸包上的点对确定最远点对。

HDU 1589 Stars Couple(计算几何求二维平面的最近点对和最远点对)


最远点对相当于求凸包中最远的两个点(先求凸包,然后n*n枚举)

最近点对 二分


#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
const int M=50005;
typedef struct Point
{
double x;
double y;
}Point;
Point p[M];
Point pp[M];
bool bo[M];
int stack[M];//form 1 to t;
double dis(Point A,Point B)
{
return sqrt((B.x-A.x)*(B.x-A.x)+(B.y-A.y)*(B.y-A.y));
}
bool cmp(Point a,Point b)
{
if(a.x<b.x)
    return true;
if(a.x>b.x)
    return false;
if(a.y<b.y)
    return true;
return false;
}
double Xdet(Point A,Point B,Point C)
{
double x1,x2,y1,y2;
x1=B.x-A.x;
y1=B.y-A.y;
x2=C.x-A.x;
y2=C.y-A.y;
return x1*y2-x2*y1;//大于0在左手边,逆时针
}
//把点集凸包化Gram_Scan算法(使用水平序)
void Gram_Scan(Point *p,int &n)//p从1-n,把点集土包化
{
int i,t;
sort(p+1,p+1+n,cmp);
for(t=0,i=1;i<=n;i++)
{
    if(i>1&&p[i].x==p[i-1].x&&p[i].y==p[i-1].y)
      continue;
    p[++t]=p[i];
}
n=t;
t=0;
memset(bo+1,true,n*sizeof(bo[0]));
if(n>0)
{
    stack[++t]=1;
    bo[stack[t]]=false;
}
if(n>1)
{
    stack[++t]=2;
    bo[stack[t]]=false;
}
if(n>2)
{
    for(i=3;i<n;i++)
      if(bo[i]&&Xdet(p[stack[t-1]],p[stack[t]],p[i])>=0)
      {
        stack[++t]=i;
        bo[i]=false;
      }
      else
      {
        while(t>=2&&Xdet(p[stack[t-1]],p[stack[t]],p[i])<0)
        {
          bo[stack[t]]=true;
          t--;
        }
        stack[++t]=i;
        bo[stack[t]]=false;
      }
   for(i=n;i>=1;i--)
     if(bo[i]&&Xdet(p[stack[t-1]],p[stack[t]],p[i])>=0)
     {
       stack[++t]=i;
       bo[i]=false;
     }
     else
     {
       while(t>=2&&Xdet(p[stack[t-1]],p[stack[t]],p[i])<0)
       {
         bo[stack[t]]=true;
         t--;
       }
       stack[++t]=i;
       bo[stack[t]]=false;
     }
     t--;
}
for(i=1;i<=t;i++)
    pp[i]=p[stack[i]];
memcpy(p+1,pp+1,t*sizeof(Point));
n=t;
}
int n,o[M],on;
int dcmp(double a,double b)
{
    if(a-b<1e-10&&b-a<1e-10)
        return 0;
    if(a>b)
        return 1;
    return -1;
}
bool cmp1(const Point &a,Point &b)
{
    return dcmp(a.x,b.x)<0;
}
bool cmp2(const int&a,const int&b)
{
    return dcmp(p[a].y,p[b].y)<0;
}
double min(double a,double b)
{
    return a<b?a:b;
}
double search(int s,int t)
{
    int mid=(s+t)/2,i,j;
    double ret=1e300;
    if(s>=t)
        return ret;
    for(i=mid;i>=s&&!dcmp(p[i].x,p[mid].x);i--);ret=search(s,i);
    for(i=mid;i<=t&&!dcmp(p[i].x,p[mid].x);i++);ret=min(ret,search(i,t));on=0;
    for(i=mid;i>=s&&dcmp(p[mid].x-p[i].x,ret)<=0;i--)o[++on]=i;
    for(i=mid+1;i<=t&&dcmp(p[i].x-p[mid].x,ret)<=0;i++)o[++on]=i;
    sort(o+1,o+on+1,cmp2);
    for(i=1;i<=on;i++)
        for(j=1;j<=10;j++)
            if(i+j<=on)
                ret=min(ret,dis(p[o[i]],p[o[i+j]]));
    return ret;
}
int main()
{
    int n,i,count=0,j;
    double shortdis,longdis;
    while(scanf("%d",&n),n)
    {
        for(i=1;i<=n;i++)
            scanf("%lf%lf",&p[i].x,&p[i].y);
        sort(p+1,p+n+1,cmp1);
        shortdis=search(1,n);
        longdis=0;
        Gram_Scan(p,n);
        for(i=1;i<=n-1;i++)
            for(j=i+1;j<=n;j++)
                if(dis(p[i],p[j])>longdis)
                    longdis=dis(p[i],p[j]);
        printf("Case %d:\n",++count);
        printf("Distance of the nearest couple is %.3lf\n",shortdis);
        printf("Distance of the most distant couple is %.3lf\n\n",longdis);
    }
    return 0;
}


### 点云最远点采样的实现方法与算法 #### 原理概述 最远点采样(Farthest Point Sampling, FPS)的核心目标是从点云数据集中选取一组具有最大间隔的代表性点[^1]。该方法通过迭代的方式逐步选择离已选点集合中最远的一个新点作为候选点,从而确保所选出的点能够尽可能均匀地分布在整个点云空间中。 #### 实现步骤 以下是基于现有研究总结出的最远点采样的具体实现流程: 1. 初始化阶段:从输入点云中随机挑选一个起始点作为第一个种子点。 2. 距离计算:对于剩余未被选择的每一个点,分别计算它们到当前已选定点集合的距离。通常采用欧几里得距离进行衡量[^3]。 3. 更新操作:找出尚未加入集合的所有点中距离最近点最远的那个点,并将其纳入已选点集合。 4. 迭代终止条件:重复上述过程直到达到预设的目标样本数量或者满足其他停止准则为止[^4]。 尽管这种方法理论上需要遍历整个点集并反复执行复杂的距离比较运算,因此时间复杂度较高;然而,在实际应用当中,借助现代硬件加速技术以及优化后的矩阵运算手段,则可以使整体效率得到显著提升。 #### PCL库中的实现 在开源项目Point Cloud Library (PCL) 中也提供了针对此功能的具体实现方案。利用PCL可以方便快捷地完成高效版本的最远点采样任务。开发者只需调用相应接口即可轻松获取经过处理之后稀疏化但仍保持原有点云特征结构的新子集[^2]。 ```cpp #include &lt;pcl/filters/voxel_grid.h&gt; #include &lt;pcl/kdtree/kdtree_flann.h&gt; void farthest_point_sampling(const pcl::PointCloud&lt;pcl::PointXYZ&gt;::Ptr &amp;input_cloud, pcl::PointCloud&lt;pcl::PointXYZ&gt;::Ptr &amp;output_cloud, int sample_num){ std::vector&lt;int&gt; indices; std::vector&lt;float&gt; distances; pcl::KdTreeFLANN&lt;pcl::PointXYZ&gt; kdtree; kdtree.setInputCloud(input_cloud); output_cloud-&gt;points.push_back(input_cloud-&gt;points[rand() % input_cloud-&gt;size()]); while(output_cloud-&gt;size()&lt;sample_num){ float max_distance=0; int index=-1; for(int i=0;i&lt;input_cloud-&gt;size();i++){ if(std::find(indices.begin(),indices.end(),i)==indices.end()){ float dist; if(kdtree.nearestKSearch(input_cloud-&gt;points[i],1,distances)&gt;0){ dist = sqrt(distances[0]); } if(max_distance&lt;dist){ max_distance=dist; index=i; } } } if(index!=-1){ output_cloud-&gt;push_back(input_cloud-&gt;at(index)); indices.push_back(index); }else{ break; } } } ``` 以上C++代码片段展示了如何使用PCL库构建自定义函数`farthest_point_sampling()`来进行最远点采样工作流的设计思路。 #### 总结 综上所述,虽然最远点采样存在一定的计算开销问题,但由于它能够在很大程度上保留原始点云的空间特性而备受青睐。特别是在诸如三维重建、物体识别等领域有着广泛的应用前景。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值