创建主要矢量“方向”的地图O(m*(s^m))
如果您有坐标范围 <0,1> 然后创建一个包含一些 s 步骤的所有矢量组合的地图,例如 11 个步骤将在 2D 中导致
(0.0,0),(0.0,0.1)...(1.0,0.9),(1.0,1.0)
将它们保存在m 维向量数组中,以便再次访问 2D 示例:
vec2 dir[s][s] =
{
{ (0.0,0.0),(0.0,0.1)...(0.0,1.0) },
{ (0.1,0.0),(0.1,0.1)...(0.1,1.0) },
...
{ (1.0,0.0),(1.0,0.1)...(1.0,1.0) }
};
在每个集合中找到与dir 中找到的向量最近的元素,对应于dis O(m*n*k*m) 中的最小距离
这是你想要的输出。如果n 对O(m*log(n)*k*m) 来说真的很大,这可能会通过二分搜索来加速。
注意s 应该选得足够大,这样才不会设置有效的解决方案。假设m 不是太大的数字,由此产生的复杂性约为O(m*n*k*(s^m))。只有在以下情况下才会更快:
O(m*(n^k)) > O(n*k*(s^m))
使用非常相似的技术(“方向”图)查看这些 QA:
[Edit1] 小 C++/VCL 例子
//---------------------------------------------------------------------------
const int K=3; // sets
const int N=3; // max set size
const int M=2; // dimensions
float set[K][N][M]=
{
{{0.1, 0.2}, {0.3, 0.4}, {0.5, 0.6}},
{{0.5, 0.9}, {0.1, 0.3}, {0.9, 0.1}},
{{0.2, 0.2}, {0.8, 0.4}, {0.5, 0.1}}
};
//---------------------------------------------------------------------------
float distance2(float *a,float *b) // |a-b|^2
{
int m;
float x,dd;
for (dd=0.0,m=0;m<M;m++)
{
x=a[m]-b[m];
dd+=x*x;
}
return dd;
}
//---------------------------------------------------------------------------
float get_closest(int *ix) // returns min distance between sets
{ // ix[K] will hold selected closest vectors from sets
const int S=11; // grid steps
const float dx=1.0/float(S-1); // grid step
int s1,s2,k,n,m,s,ss1,ss2;
float x1,x2,d,d1,d2;
float dir[S][S][M],dis[S][S];
// create dir[][]
for (s1=0,x1=0.0;s1<S;s1++,x1+=dx)
for (s2=0,x2=0.0;s2<S;s2++,x2+=dx)
{
m=0;
dir[s1][s2][m]=x1; m++;
dir[s1][s2][m]=x2; m++;
}
// compute dis[][] and its minimum dis[ss1][ss2]
ss1=0; ss2=0;
for (s1=0;s1<S;s1++)
for (s2=0;s2<S;s2++)
{
// max distance between set[] and dir[s1][s2]
for (d2=0.0,k=0;k<K;k++)
{
// min distance between set[k][] and dir[s1][s2]
for (d1=0.0,n=0;n<N;n++)
{
d=distance2(dir[s1][s2],set[k][n]);
if ((n==0)||(d1>d)) d1=d;
}
if (d2<d1) d2=d1;
}
dis[s1][s2]=d2;
// remember smallest one
if (dis[ss1][ss2]>dis[s1][s2]){ ss1=s1; ss2=s2; }
}
// find corresponding indexes from set[][]
for (k=0;k<K;k++)
for (d1=0.0,ix[k]=0,n=0;n<N;n++)
{
d=distance2(dir[ss1][ss2],set[k][n]);
if ((n==0)||(d1>d)){ d1=d; ix[k]=n; }
}
// compute real distance
for (d1=0.0,m=0;m<M;m++)
{
for (k=0;k<K;k++)
{
d=set[k][ix[k]][m];
if (k==0){ x1=d; x2=d; }
if (x1>d) x1=d;
if (x2<d) x2=d;
}
d=x2-x1; d1+=d*d;
}
return sqrt(d1);
}
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner):TForm(Owner)
{
AnsiString s;
int k,n,m,ix[K];
mm_log->Lines->Add(get_closest(ix));
for (k=0;k<K;k++)
{
for (n=ix[k],s="",m=0;m<M;m++) s+=AnsiString().sprintf("%3.1f ",set[k][n][m]);
mm_log->Lines->Add(s);
}
}
//-------------------------------------------------------------------------
只需忽略 VCL 的东西(最后一个使用 get_closest 并打印其结果的函数),重要的东西是函数 get_closest,它返回每个集合中最近向量的索引数组。这里的结果:
0.141421367827692
0.1 0.2
0.1 0.3
0.2 0.2
代码要求所有集合的长度相同,对于变量一,您只需稍微调整一下(n 的所有循环)
如果内存是一个问题请注意,如果所有迭代都移到相同的循环中,则数组dir,dis 可能会被删除...
如果您想为任何维度做好准备,请参阅:
寻找nested_for,您可以使用它轻松实现s^m 循环,而无需任何奇怪的黑客攻击......