假设线段中有25个点,并且这些点可能分布不均匀(空间),如下图所示:
我的问题是如何在这25个点中选择10个点,以便这10个点可以尽可能在空间上均匀分布。在想法情况下,选定的点应该是这样的:
修改 诚然,如果我能说出“均匀分配”的标准,这个问题就会变得更加优雅。我所知道的是我对选定点的预期:如果我将线段分成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;
}
结果显示在下图中,其中所选点表示为绿色:
答案 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中轻松实现):
Turk,Steffen Gauglitz Luca Foschini Matthew和TobiasHöllerer。 “EFFICIENTLY SELECTING SPATIALLY DISTRIBUTED KEYPOINTS FOR VISUAL TRACKING.”
Brown,Matthew,Richard Szeliski和Simon Winder。 “Multi-image matching using multi-scale oriented patches.”计算机视觉与模式识别,2005年.CVPR 2005. IEEE计算机学会会议。卷。 1. IEEE,2005。
第二篇论文与您的问题关系不大,但它描述了基本的ANMS算法。第一篇论文提供了更快的解决方我想两者都会在1D中获得适量的积分(~10K)。