选择均匀分布点算法

时间:2013-08-14 08:45:08

标签: algorithm stl-algorithm

假设线段中有25个点,并且这些点可能分布不均匀(空间),如下图所示: enter image description here

我的问题是如何在这25个点中选择10个点,以便这10个点可以尽可能在空间上均匀分布。在想法情况下,选定的点应该是这样的: enter image description here

修改 诚然,如果我能说出“均匀分配”的标准,这个问题就会变得更加优雅。我所知道的是我对选定点的预期:如果我将线段分成10个相等的线段。我希望每个小线段都应该有一个点。当然可能会发生在一些小线段中我们找不到代表点。在这种情况下,我将诉诸其具有代表点的邻近小线段。在下一步中,我将进一步将所选择的相邻段分成两部分:如果每个部分都有代表点,那么将解决空代表点问题。如果我们在一个小线段中找不到代表点,我们可以进一步将它分成更小的部分。或者我们可以求助于下一个相邻的线段。

修改 使用动态编程,可实现的解决方案如下:

#include <iostream>
#include <vector>
using namespace std;


struct  Note
{
    int previous_node;
    double cost;

};
typedef struct Note Note;

int main()
{

    double dis[25] = 
    {0.0344460805029088, 0.118997681558377, 0.162611735194631,
    0.186872604554379, 0.223811939491137, 0.276025076998578,
    0.317099480060861, 0.340385726666133, 0.381558457093008,
    0.438744359656398, 0.445586200710900, 0.489764395788231,
    0.498364051982143, 0.585267750979777, 0.646313010111265,
    0.655098003973841, 0.679702676853675, 0.694828622975817,
    0.709364830858073, 0.754686681982361, 0.765516788149002,
    0.795199901137063, 0.823457828327293, 0.950222048838355, 0.959743958516081};

    Note solutions[25];
    for(int i=0; i<25; i++)
    {
        solutions[i].cost = 1000000;
    }
    solutions[0].cost = 0;
    solutions[0].previous_node = 0;



    for(int i=0; i<25; i++)
    {
        for(int j= i-1; j>=0; j--)
        {
            double tempcost = solutions[j].cost + std::abs(dis[i]-dis[j]-0.1);
            if (tempcost<solutions[i].cost)
            {
                solutions[i].previous_node = j;
                solutions[i].cost = tempcost;
            }

        }
    }
    vector<int> selected_points_index;
    int i= 24;
    selected_points_index.push_back(i);
    while (solutions[i].previous_node != 0)
    {
        i = solutions[i].previous_node;
        selected_points_index.push_back(i);

    }
    selected_points_index.push_back(0);

    std::reverse(selected_points_index.begin(),selected_points_index.end());

    for(int i=0; i<selected_points_index.size(); i++)
        cout<<selected_points_index[i]<<endl;





    return 0;
}

结果显示在下图中,其中所选点表示为绿色:

enter image description here

3 个答案:

答案 0 :(得分:3)

在一个好的,可能O(n^2)解决方案出现之前,请使用此近似值:

将范围分成10个相等大小的箱子。选择最靠近每个箱子中心的每个箱子中的点。完成工作。

如果您发现任何垃圾箱都是空的,请选择较少数量的垃圾箱,然后重试。

如果没有关于您试图实施的科学模型的信息,很难(a)建议更合适的算法和/或(b)证明更复杂算法的计算工作量。

答案 1 :(得分:2)

让{x [i]}成为您的有序点集。我想你需要做的是找到10个点{y [i]}的子集,它最小化\ sum {| y [i] -y [i-1] -0.1 |} y [-1] = 0

现在,如果您将配置视为强连接有向图,其中每个节点是25个双精度数中的一个,并且每个边的成本是| y [i] -y [i-1] -0.1 |,应该能够用Dijkstra算法解决O(n ^ 2 + nlogn)时间的问题。

另一个可能导致更好结果的想法是使用动态编程:如果元素x [i]是我们求解的一部分,则总最小值是到达x [i]的最小值之和点加上最小点得到最终点,所以你可以为每个点写一个最小解,从最小点开始,并在下一个点之间使用它的前任之间的最小值。

请注意,您可能需要做一些额外的工作,从解决方案集中选择10点的子集。

修改

我在c#中写道:

  for (int i = 0; i < 25; i++)
  {
    for (int j = i-1; j > 0; j--)
    {
      double tmpcost = solution[j].cost + Math.Abs(arr[i] - arr[j] - 0.1);
      if (tmpcost < solution[i].cost)
      {
         solution[i].previousNode = j;
         solution[i].cost = tmpcost;
      }
    }
  }

我没有做过很多测试,如果25个元素中的“漏洞”非常宽,可能会出现问题,导致解决方案短于10个元素......但它只是给你一些想法可以解决:)

答案 2 :(得分:2)

如果点是加权的,您可以使用自适应非最大抑制(ANMS)算法找到近似解。该算法选择n 最佳点,同时保持它们在空间上的良好分布(大多数分布在空间中)。

我猜您可以根据您的分配标准指定点权重 - 例如距您选择的均匀格子的距离。我认为格子应该有n-1个区域以获得最佳结果。

您可以查阅以下讨论2D案例的论文(该算法可以在1D中轻松实现):

  1. Turk,Steffen Gauglitz Luca Foschini Matthew和TobiasHöllerer。 “EFFICIENTLY SELECTING SPATIALLY DISTRIBUTED KEYPOINTS FOR VISUAL TRACKING.

  2. Brown,Matthew,Richard Szeliski和Simon Winder。 “Multi-image matching using multi-scale oriented patches.”计算机视觉与模式识别,2005年.CVPR 2005. IEEE计算机学会会议。卷。 1. IEEE,2005。

  3. 第二篇论文与您的问题关系不大,但它描述了基本的ANMS算法。第一篇论文提供了更快的解决方我想两者都会在1D中获得适量的积分(~10K)。