我正在尝试为具有统一维度n
的3d数组找到遍历顺序。因此,遍历顺序应按其到立方体中心的距离递增(具有相等索引的单元格的顺序是任意的) 。
2d阵列的示例:
7 4 8
3 0 1
6 2 5
这基本上是Manhattan metric中的距离:
2 1 2
1 0 1
2 1 2
遍历相对于原点的相对坐标:
[ 0, 0]
[ 1, 0]
[ 0,-1]
[-1, 0]
[ 0, 1]
[ 1,-1]
[-1,-1]
[-1, 1]
[ 1, 1]
我知道解决这个问题的一些方法,例如预先计算所有索引并根据它们与原点的距离对它们进行排序。但是,由于此算法旨在在 GPU 上执行,因此存在一些限制:
在搜索解决方案时,我偶然发现了这个问题,这正是我倾向于解决的问题,虽然包含了一个不符合指定要求的树结构,但已接受的答案:3D Array Traversal in Different Order
我还想到了一种使用球面坐标创建索引的方法,遗憾的是这种方法不会产生正确的顺序。为3d数组生成给定遍历顺序的适当算法是什么?
编辑:Stormwind为给定的问题提供了一个很好的替代描述:“[问题]实际上是关于将寻址从一个空间转换到另一个空间。在1维和2维之间转换很简单,就像1,2,3,......到(1,1),(1,2)(2,1)......但这更像是从升序的1维(或至少是正方形)转换为“上升的八面体分层“空间,当”上升“意味着”最内层第一“,此外还有每个层面上现有的(尽管是任意的)递增顺序。”
答案 0 :(得分:7)
在思考了一段时间之后,我想出了一个想法,将3d数组表示为一系列带有方向的节点:+i
,-i
,+j
,{{ 1}},-j
,+k
。
对于二维数组,只有三个规则就足够了:
-k
将增加第二个索引,节点+j
将减少第一个索引。-i
和Main
。主轴有一个索引Secondary
。对0
Main
和i
轴节点(我称之为j
和I
)的每次迭代都会产生J
节点顺时针旋转90度:
Secondary
+I -> -j
-J -> -i
-I -> +j
+J -> +i
的奇数值,节点的生命周期等于(n-1)/2
(对于偶数值,请参见下面的代码)。在生命周期变为0之后,应该删除节点。要启用第三维,应该应用另一条规则:
n
轴方向(此处为深度)的第三类节点在每次迭代中生成k
和I
轴的集合:
J
+K -> +I, -J, -I, +J
以下是它的外观:
通过这种方法,元素将按照Manhattan distance自动排序,如Arturo Menchaca解决方案。
这是我所描述的python代码。有很多改进的空间,这只是一个概念证明。它没有排序,没有递归,我也没有看到任何离线计算。 它还包含一些测试。 Run
-K -> +I, -J, -I, +J
用于存储索引的助手类:
NO = ( 0, 0, 0, 2, 0)
Pi = (+1, 0, 0, 0, 0)
PI = (+1, 0, 0, 0, 1)
Pj = ( 0,+1, 0, 0, 0)
PJ = ( 0,+1, 0, 0, 1)
PK = ( 0, 0,+1, 0, 2)
Mi = (-1, 0, 0, 1, 0)
MI = (-1, 0, 0, 1, 1)
Mj = ( 0,-1, 0, 1, 0)
MJ = ( 0,-1, 0, 1, 1)
MK = ( 0, 0,-1, 1, 2)
# i j k ^ ^
# | Id for comparison
# Lifetime index
PRODUCE = {
PI: [ Mj ], # +I -> -j
MJ: [ Mi ], # -J -> -i
MI: [ Pj ], # -I -> +j
PJ: [ Pi ], # +J -> +i
NO: [ NO ],
Pi: [ NO ],
Pj: [ NO ],
Mi: [ NO ],
Mj: [ NO ],
PK: [ PI, MI, PJ, MJ ], # +K -> +I, -J, -I, +J
MK: [ PI, MI, PJ, MJ ], # -K -> +I, -J, -I, +J
}
class Index:
LastDistance = 0
NumberOfVisits = 0
MinIndex = 0
MaxIndex = 0
def __init__(self, i, j, k, lifetime, direction):
self.globalLifetime = lifetime
self.direction = direction
# Assign parent's position
self.i = i
self.j = j
self.k = k
# Step away from parent
self.lifetime = lifetime[direction[3]]
self.step()
def isLive(self):
return self.lifetime > 0
def visit(self):
Index.NumberOfVisits += 1
distance = self.distance()
if distance < Index.LastDistance:
raise NameError("Order is not preserved")
Index.LastDistance = distance
Index.MinIndex = min(self.i, Index.MinIndex)
Index.MinIndex = min(self.j, Index.MinIndex)
Index.MinIndex = min(self.k, Index.MinIndex)
Index.MaxIndex = max(self.i, Index.MaxIndex)
Index.MaxIndex = max(self.j, Index.MaxIndex)
Index.MaxIndex = max(self.k, Index.MaxIndex)
print("[{}, {}, {}]".format(self.i, self.j, self.k))
def step(self):
# Move in your direction
self.i += self.direction[0]
self.j += self.direction[1]
self.k += self.direction[2]
def iterate(self):
self.lifetime -= 1
def produce(self, result):
for direction in PRODUCE[self.direction]:
self.create(direction, result)
def create(self, direction, result):
index = Index(self.i, self.j, self.k, self.globalLifetime, direction)
if index.isLive():
result.append(index)
def distance(self):
# Manhattan Distance
return abs(self.i) + abs(self.j) + abs(self.k)
def Traverse(N):
TotalNumber = N*N*N
halfA = halfB = (N-1)/2
if N % 2 == 0:
halfA = N/2
halfB = N/2-1
MinIndex = -min(halfB, halfA)
MaxIndex = max(halfB, halfA)
lifetime = (halfA, halfB, 0)
SecondaryNodes = []
MainNodes = []
KNodes = []
# visit center
center = Index(0, 0, 0, lifetime, NO)
center.visit()
center.create(PI, MainNodes)
center.create(MI, MainNodes)
center.create(PJ, MainNodes)
center.create(MJ, MainNodes)
center.create(PK, KNodes)
center.create(MK, KNodes)
while len(SecondaryNodes) + len(MainNodes) + len(KNodes) > 0:
# First - visit all side nodes
temp = []
for m in SecondaryNodes:
m.visit()
m.step()
m.iterate()
# Save node only if it is alive
if m.isLive():
temp.append(m)
SecondaryNodes = temp
# Second - visit all main nodes as they may produce secondary nodes
temp = []
for m in MainNodes:
m.visit() # 1 - Visit
m.produce(SecondaryNodes) # 2 - Produce second
m.step() # 3 - Step
m.iterate() # 4 - Lose a life
if m.isLive():
temp.append(m)
MainNodes = temp
# Third - visit all K nodes as they may produce main nodes
temp = []
for m in KNodes:
m.visit()
m.produce(MainNodes)
m.step()
m.iterate()
if m.isLive():
temp.append(m)
KNodes = temp
if TotalNumber != Index.NumberOfVisits:
raise NameError("Number of visited elements does not match {}/{}".format(Index.NumberOfVisits, TotalNumber))
if MinIndex != Index.MinIndex:
raise NameError("Minimal index is out of bounds {}/{}".format(Index.MinIndex, MinIndex))
if MaxIndex != Index.MaxIndex:
raise NameError("Maximal index is out of bounds {}/{}".format(Index.MaxIndex, MaxIndex))
Traverse(6)
以正确方向迭代class Index:
def __init__(self, i, j, k, lifetime):
self.i = i
self.j = j
self.k = k
self.lifetime = lifetime
def visit(self):
print("[{}, {}, {}]".format(self.i, self.j, self.k))
个节点的函数集:
Main
迭代第三维def StepMainPlusI(mainPlusI, minusJ, lifetime):
result = []
for m in mainPlusI:
if lifetime > 0:
minusJ.append(Index(m.i, m.j-1, m.k, lifetime))
m.lifetime -= 1
m.i += 1
if m.lifetime > 0:
result.append(m)
return result
def StepMainMinusJ(mainMinusJ, minusI, lifetime):
result = []
for m in mainMinusJ:
if lifetime > 0:
minusI.append(Index(m.i-1, m.j, m.k, lifetime))
m.lifetime -= 1
m.j -= 1
if m.lifetime > 0:
result.append(m)
return result
def StepMainMinusI(mainMinusI, plusJ, lifetime):
result = []
for m in mainMinusI:
if lifetime > 0:
plusJ.append(Index(m.i, m.j+1, m.k, lifetime))
m.lifetime -= 1
m.i -= 1
if m.lifetime > 0:
result.append(m)
return result
def StepMainPlusJ(mainPlusJ, plusI, lifetime):
result = []
for m in mainPlusJ:
if lifetime > 0:
plusI.append(Index(m.i+1, m.j, m.k, lifetime))
m.lifetime -= 1
m.j += 1
if m.lifetime > 0:
result.append(m)
return result
节点的函数集:
K
当def StepMainPlusK(mainPlusK, mainPlusI, mainMinusI, mainPlusJ, mainMinusJ, lifetimeA, lifetimeB):
result = []
for m in mainPlusK:
if lifetimeA > 0:
mainPlusI.append(Index(+1, 0, m.k, lifetimeA))
mainPlusJ.append(Index(0, +1, m.k, lifetimeA))
if lifetimeB > 0:
mainMinusI.append(Index(-1, 0, m.k, lifetimeB))
mainMinusJ.append(Index(0, -1, m.k, lifetimeB))
m.lifetime -= 1
m.k += 1
if m.lifetime > 0:
result.append(m)
return result
def StepMainMinusK(mainMinusK, mainPlusI, mainMinusI, mainPlusJ, mainMinusJ, lifetimeA, lifetimeB):
result = []
for m in mainMinusK:
if lifetimeA > 0:
mainPlusI.append(Index(+1, 0, m.k, lifetimeA))
mainPlusJ.append(Index(0, +1, m.k, lifetimeA))
if lifetimeB > 0:
mainMinusI.append(Index(-1, 0, m.k, lifetimeB))
mainMinusJ.append(Index(0, -1, m.k, lifetimeB))
m.lifetime -= 1
m.k -= 1
if m.lifetime > 0:
result.append(m)
return result
为奇数且一半可能小于另一半时,这两个函数有两个不同的生命周期参数。我按标志划分了它们 - 负面导向的指数会降低一半。
迭代n
个节点的函数集:
Secondary
主要功能:
def StepPlusI(plusI):
result = []
for m in plusI:
m.i += 1
m.lifetime -= 1
if m.lifetime > 0:
result.append(m)
return result
def StepMinusI(minusI):
result = []
for m in minusI:
m.i -= 1
m.lifetime -= 1
if m.lifetime > 0:
result.append(m)
return result
def StepPlusJ(plusJ):
result = []
for m in plusJ:
m.j += 1
m.lifetime -= 1
if m.lifetime > 0:
result.append(m)
return result
def StepMinusJ(minusJ):
result = []
for m in minusJ:
m.j -= 1
m.lifetime -= 1
if m.lifetime > 0:
result.append(m)
return result
实例Code
答案 1 :(得分:5)
Octant symmetry
立方矩阵中距离中心一定距离曼哈顿的单元形成一个八面体,它与穿过立方体中心的xy,xz和yz平面对称。
这意味着您只需要在立方体的第一个octant中找到构成八面体一面的单元格,然后镜像它们以获得其他7个八分圆中的单元格。因此,从中心(距离0)到角单元(最大距离= 3×n / 2),问题被简化为从对角线穿过立方体的第一个八分圆(其本身是立方体)。
查找坐标的算法
从第一个八分圆中的(0,0,0)单元(即形成八面体的一个面,垂直于立方体的对角线的单元)中找到与某个曼哈顿距离的单元格,意味着找到坐标(x,y,z)与该距离相加的单元格。因此,在5x5x5八分圆的示例中,距离3处的单元格是具有坐标的单元格:
(3,0,0)(2,1,0)(1,2,0)(0,3,0)
(2,0,1)(1,1,1)(0,2,1)
(1,0,2)(0,1,2)
(0,0,3)
你会注意到与距离分区的相似性(实际上,它是一个所谓的weak composition,有界长度为3)。
使用三个嵌套循环可以轻松找到这些组合;唯一的复杂因素是每个维度的距离被限制为n / 2,因此你必须跳过x和/或y的值,这些值对于z没有值,所以x,y和z与距离相加;这就是JavaScript代码示例中的min()
和max()
以及C中的xmin
,xmax
,ymin
和ymax
变量代码示例适用于。
在一个偶数大小的立方体中镜像细胞是直截了当的;在奇数大小的立方体中,单元在其坐标为零的维度中不被镜像(即,当单元位于对称平面中时)。这就是在代码示例中检查x,y或z是否等于零的原因。
并行编程
我对GPU编程知之甚少,但我认为你可以完全平行算法。对于外环的每次迭代(即对于每个距离),一旦计算出x的最小值和最大值,就可以并行运行具有不同x值的迭代。然后,对于x的每个值,一旦计算出y的最小值和最大值,就可以并行运行具有不同y值的迭代。最后,对于(x,y,z)的每个坐标集,可以并行运行与其他八分圆的镜像。
代码示例1(JavaScript)
(运行代码片段以查看9x9x9矩阵的内向外遍历,如图所示。)
function insideOut(n) {
var half = Math.ceil(n / 2) - 1;
for (var d = 0; d <= 3 * half; d++) {
for (var x = Math.max(0, d - 2 * half); x <= Math.min(half, d); x++) {
for (var y = Math.max(0, d - x - half); y <= Math.min(half, d - x); y++) {
document.write("<br>distance " + d + " (±" + x + ",±" + y + ",±" + (d - x - y) + ") → ");
n % 2 ? mirrorOdd(x, y, d - x - y) : mirrorEven(x, y, d - x - y);
}
}
}
function mirrorEven(x, y, z) {
for (var i = 1; i >= 0; --i, x *= -1) {
for (var j = 1; j >= 0; --j, y *= -1) {
for (var k = 1; k >= 0; --k, z *= -1) {
visit(half + x + i, half + y + j, half + z + k);
}
}
}
}
function mirrorOdd(x, y, z) {
for (var i = 0; i < (x ? 2 : 1); ++i, x *= -1) {
for (var j = 0; j < (y ? 2 : 1); ++j, y *= -1) {
for (var k = 0; k < (z ? 2 : 1); ++k, z *= -1) {
visit(half + x, half + y, half + z);
}
}
}
}
function visit(x, y, z) {
document.write("(" + x + "," + y + "," + z + ") " );
}
}
insideOut(9);
代码示例2(C)
为简单起见,可以展开镜像功能。实际上,整个算法只包含3个嵌套循环和简单的整数计算。
void mirrorEven(unsigned int x, unsigned int y, unsigned int z, unsigned int h) {
visit(h+x+1, h+y+1, h+z+1);
visit(h+x+1, h+y+1, h-z);
visit(h+x+1, h-y, h+z+1);
visit(h+x+1, h-y, h-z);
visit(h-x, h+y+1, h+z+1);
visit(h-x, h+y+1, h-z);
visit(h-x, h-y, h+z+1);
visit(h-x, h-y, h-z);
}
void mirrorOdd(unsigned int x, unsigned int y, unsigned int z, unsigned int h) {
visit(h+x, h+y, h+z);
if ( z) visit(h+x, h+y, h-z);
if ( y ) visit(h+x, h-y, h+z);
if ( y && z) visit(h+x, h-y, h-z);
if (x ) visit(h-x, h+y, h+z);
if (x && z) visit(h-x, h+y, h-z);
if (x && y ) visit(h-x, h-y, h+z);
if (x && y && z) visit(h-x, h-y, h-z);
}
void insideOut(unsigned int n) {
unsigned int d, x, xmin, xmax, y, ymin, ymax, half = (n-1)/2;
for (d = 0; d <= 3*half; d++) {
xmin = d < 2*half ? 0 : d-2*half;
xmax = d < half ? d : half;
for (x = xmin; x <= xmax; x++) {
ymin = d < x+half ? 0 : d-x-half;
ymax = d > x+half ? half : d-x;
for (y = ymin; y <= ymax; y++) {
if (n%2) mirrorOdd(x, y, d-x-y, half);
else mirrorEven(x, y, d-x-y, half);
}
}
}
}
答案 2 :(得分:4)
[我在解决方案中使用Manhattan distance]
为简单起见,让我们开始假设奇数维([2N+1, 2N+1, 2N+1]
)
使用曼哈顿距离中心([0,0,0]
)与点之间的最大距离为3N
([N,N,N]
,[N,N,-N
], ...)
所以,基本上这个想法是找到一种方法来生成具有特定距离的所有坐标。然后从距离0
开始到3N
生成这些坐标。
要生成距离为[X,Y,Z]
的坐标K
,我们需要的是X
,Y
,Z
之间的所有数字-N
1}}和N
使得ABS(X) + ABS(Y) + ABS(Z) == K
。这可以通过以下方式完成:
FUNC COORDS_AT_DIST(K)
FOR X = -MIN(N, K) TO MIN(N, K)
FOR Y = -MIN(N, K - ABS(X)) TO MIN(N, K - ABS(X))
LET Z = K - ABS(X) - ABS(Y)
IF Z <= N
VISIT(X, Y, Z)
IF Z != 0
VISIT(X, Y, -Z)
然后,像这样使用这个函数:
FOR K = 0 TO 3N
COORDS_AT_DIST(K)
此代码访问所有坐标,其中[-N,-N,-N]
和[N,N,N]
之间的值根据与[0,0,0]
的距离排序。
现在,为了处理偶数维度,我们还需要一些额外的检查,因为维度L
的坐标值介于[-(L/2-1),-(L/2-1),-(L/2-1)]
和[L/2,L/2,L/2]
之间。
这样的事情:
FUNC VISIT_COORDS_FOR_DIM(L)
LET N = L/2 //Integer division
FOR K = 0 TO 3N
FOR X = -MIN(N - REM(L+1, 2), K) TO MIN(N, K)
FOR Y = -MIN(N - REM(L+1, 2), K - ABS(X)) TO MIN(N, K - ABS(X))
LET Z = K - ABS(X) - ABS(Y)
IF Z <= N
VISIT(X, Y, Z)
IF Z != 0 && (REM(L, 2) != 0 || Z < N)
VISIT(X, Y, -Z)
为了清楚起见:
MIN(X, Y): Minimum value between X and Y
ABS(X): Absolute value of X
REM(X, Y): Remainder after division of X by Y
VISIT(X, Y, Z): Visit the generated coordinate (X, Y, Z)
将VISIT_COORDS_FOR_DIM
功能与L=3
一起使用即可获得:
1. [0, 0, 0] DISTANCE: 0
2. [-1, 0, 0] DISTANCE: 1
3. [0, -1, 0] DISTANCE: 1
4. [0, 0, -1] DISTANCE: 1
5. [0, 0, 1] DISTANCE: 1
6. [0, 1, 0] DISTANCE: 1
7. [1, 0, 0] DISTANCE: 1
8. [-1, -1, 0] DISTANCE: 2
9. [-1, 0, -1] DISTANCE: 2
10. [-1, 0, 1] DISTANCE: 2
11. [-1, 1, 0] DISTANCE: 2
12. [0, -1, -1] DISTANCE: 2
13. [0, -1, 1] DISTANCE: 2
14. [0, 1, -1] DISTANCE: 2
15. [0, 1, 1] DISTANCE: 2
16. [1, -1, 0] DISTANCE: 2
17. [1, 0, -1] DISTANCE: 2
18. [1, 0, 1] DISTANCE: 2
19. [1, 1, 0] DISTANCE: 2
20. [-1, -1, -1] DISTANCE: 3
21. [-1, -1, 1] DISTANCE: 3
22. [-1, 1, -1] DISTANCE: 3
23. [-1, 1, 1] DISTANCE: 3
24. [1, -1, -1] DISTANCE: 3
25. [1, -1, 1] DISTANCE: 3
26. [1, 1, -1] DISTANCE: 3
27. [1, 1, 1] DISTANCE: 3
对于L=4
:
1. [0, 0, 0] DISTANCE: 0 33. [1, -1, -1] DISTANCE: 3
2. [-1, 0, 0] DISTANCE: 1 34. [1, -1, 1] DISTANCE: 3
3. [0, -1, 0] DISTANCE: 1 35. [1, 0, 2] DISTANCE: 3
4. [0, 0, -1] DISTANCE: 1 36. [1, 1, -1] DISTANCE: 3
5. [0, 0, 1] DISTANCE: 1 37. [1, 1, 1] DISTANCE: 3
6. [0, 1, 0] DISTANCE: 1 38. [1, 2, 0] DISTANCE: 3
7. [1, 0, 0] DISTANCE: 1 39. [2, -1, 0] DISTANCE: 3
8. [-1, -1, 0] DISTANCE: 2 40. [2, 0, -1] DISTANCE: 3
9. [-1, 0, -1] DISTANCE: 2 41. [2, 0, 1] DISTANCE: 3
10. [-1, 0, 1] DISTANCE: 2 42. [2, 1, 0] DISTANCE: 3
11. [-1, 1, 0] DISTANCE: 2 43. [-1, -1, 2] DISTANCE: 4
12. [0, -1, -1] DISTANCE: 2 44. [-1, 1, 2] DISTANCE: 4
13. [0, -1, 1] DISTANCE: 2 45. [-1, 2, -1] DISTANCE: 4
14. [0, 0, 2] DISTANCE: 2 46. [-1, 2, 1] DISTANCE: 4
15. [0, 1, -1] DISTANCE: 2 47. [0, 2, 2] DISTANCE: 4
16. [0, 1, 1] DISTANCE: 2 48. [1, -1, 2] DISTANCE: 4
17. [0, 2, 0] DISTANCE: 2 49. [1, 1, 2] DISTANCE: 4
18. [1, -1, 0] DISTANCE: 2 50. [1, 2, -1] DISTANCE: 4
19. [1, 0, -1] DISTANCE: 2 51. [1, 2, 1] DISTANCE: 4
20. [1, 0, 1] DISTANCE: 2 52. [2, -1, -1] DISTANCE: 4
21. [1, 1, 0] DISTANCE: 2 53. [2, -1, 1] DISTANCE: 4
23. [2, 0, 0] DISTANCE: 2 54. [2, 0, 2] DISTANCE: 4
23. [-1, -1, -1] DISTANCE: 3 55. [2, 1, -1] DISTANCE: 4
24. [-1, -1, 1] DISTANCE: 3 56. [2, 1, 1] DISTANCE: 4
25. [-1, 0, 2] DISTANCE: 3 57. [2, 2, 0] DISTANCE: 4
26. [-1, 1, -1] DISTANCE: 3 58. [-1, 2, 2] DISTANCE: 5
27. [-1, 1, 1] DISTANCE: 3 59. [1, 2, 2] DISTANCE: 5
28. [-1, 2, 0] DISTANCE: 3 60. [2, -1, 2] DISTANCE: 5
29. [0, -1, 2] DISTANCE: 3 61. [2, 1, 2] DISTANCE: 5
30. [0, 1, 2] DISTANCE: 3 62. [2, 2, -1] DISTANCE: 5
31. [0, 2, -1] DISTANCE: 3 63. [2, 2, 1] DISTANCE: 5
32. [0, 2, 1] DISTANCE: 3 64. [2, 2, 2] DISTANCE: 6
此解决方案具有以下优点:不需要任何特殊的数据结构,甚至不需要数组。
另一个解决方案可能是你可以使用一个队列(用数组实现起来并不困难),而且从中心开始,3D布尔(或int)数组就像BFS一样。
首先,要定义什么是邻居,可以使用移动数组,例如:
如果共享一个共同的一面(Manhattan distance),则两个单元格是邻居:
DX = { 1, 0, 0, -1, 0, 0 }
DY = { 0, 1, 0, 0, -1, 0 }
DZ = { 0, 0, 1, 0, 0, -1 }
如果共享共同边缘,则两个单元格是邻居:
DX = { 1, 0, 0, -1, 0, 0, 1, 1, 0, -1, -1, 0, 1, 1, 0, -1, -1, 0 }
DY = { 0, 1, 0, 0, -1, 0, 1, 0, 1, 1, 0, -1, -1, 0, 1, -1, 0, -1 }
DZ = { 0, 0, 1, 0, 0, -1, 0, 1, 1, 0, 1, 1, 0, -1, -1, 0, -1, -1 }
如果共享一个共同的角落(Chebyshev distance),则两个单元格是邻居:
DX = { 1, 0, 0, -1, 0, 0, 1, 1, 0, -1, -1, 0, 1, 1, 0, -1, -1, 0, 1, -1, 1, 1, -1, -1, 1, -1 }
DY = { 0, 1, 0, 0, -1, 0, 1, 0, 1, 1, 0, -1, -1, 0, 1, -1, 0, -1, 1, 1, -1, 1, -1, 1, -1, -1 }
DZ = { 0, 0, 1, 0, 0, -1, 0, 1, 1, 0, 1, 1, 0, -1, -1, 0, -1, -1, 1, 1, 1, -1, 1, -1, -1, -1 }
现在,使用队列,您可以从中心位置开始,然后添加邻居,然后添加邻居的邻居,依此类推。在每次迭代中,您都可以访问每个生成的位置。
这样的事情:
DX = { 1, 0, 0, -1, 0, 0 }
DY = { 0, 1, 0, 0, -1, 0 }
DZ = { 0, 0, 1, 0, 0, -1 }
VISIT_COORDS_FOR_DIM(L):
LET N = L/2
IF (REM(L, 2) == 0)
N--
V: BOOLEAN[L, L, L]
Q: QUEUE<POINT3D>
V[N, N, N] = TRUE
ENQUEUE(Q, POINT3D(N, N, N))
WHILE COUNT(Q) > 0
P = DEQUEUE(Q)
VISIT(P.X - N, P.Y - N, P.Z - N) //To Transform coords to [-N, N] range.
FOR I = 0 TO LENGTH(DX) - 1
LET X = P.X + DX[I]
LET Y = P.Y + DY[I]
LET Z = P.Z + DZ[I]
IF IS_VALID_POS(L, X, Y, Z) && V[X, Y, Z] == FALSE
V[X, Y, Z] = TRUE
ENQUEUE(Q, POINT3D(X, Y, Z))
IS_VALID_POS(L, X, Y, Z)
RETURN X >= 0 && X < L &&
Y >= 0 && Y < L &&
Z >= 0 && Z < L
使用过的功能:
REM(X, Y): Remainder after division of X by Y
ENQUEUE(Q, X): Enqueue element X in queue Q
DEQUEUE(Q): Dequeue first element from queue Q
COUNT(Q): Number of elements in queue Q
VISIT(X, Y, Z): Visit the generated coordinate (X, Y, Z)
此解决方案具有以下优点:您可以使用移动数组定义两个位置是邻居。
答案 3 :(得分:3)
获得这个问题的有效算法的关键是看到它背后的几何。您要求的是为N的每个连续值求解Diophantine equation N = a ^ 2 + b ^ 2 + c ^ 2,以任何顺序枚举这样的解。这个方程的解是半径为N的球体上的积分点。所以从某种意义上说,你的问题是枚举球体。
首先,应该清楚的是,这里的难题是枚举坐标(a,b,c)的非负解。对于每个这样的坐标,从坐标平面周围的镜像对称有八个其他解,因为a ^ 2 =( - a)^ 2等(一般情况下。如果a,b,c中的一个或多个为零,则得到通过置换坐标使得a&lt; = b&lt; = c。进一步对称。这是枚举的简单部分。
球体枚举算法的本质是考虑两组近似于半径为N的球体的点:一组由具有范数的点组成,并且#34;略小于#34;比N和一个由他们的格子邻居组成的规范&#34;稍微大一些&#34;比N或等于N.&#34;略少于&#34;对于点(a,b,c),a ^ 2 + b ^ 2 + c ^ 2&lt; N,但是一个或多个点(a + 1,b,c),(a,b + 1,c)或(a,b,c + 1)具有范数&gt; = N.至于代码,你不需要代表&#34;稍微少一些&#34;组;它已被处理完毕。它足以创建一个更大的&#34;&#34;按照他们的标准排序。
算法的每一步都变为&#34;略大的&#34;为N + 1设置N为一。删除堆的最少元素,比如(a,b,c)。现在将具有更大范数的最近邻点添加到堆中,三个点(a + 1,b,c),(a,b + 1,c)和(a,b,c + 1)。其中一些人可能已经在那里;我会回过头来看看。将增量点添加到堆上时,需要它的规范。你做不,但需要从头开始计算。依靠身份(a + 1)^ 2 - a ^ 2 = 2a + 1.换句话说,你不需要任何乘法运算来计算这些规范。根据您的GPU,您可以计算表达式a&lt;&lt; 1 + 1或者a + a + 1。
您还可以优化检查堆上的现有点。每个点有六个直接点阵邻居。具有最小范数的格子邻居将是第一个添加它的人。假设a&lt; b&lt; c表示点(a,b,c)。其规范最小的邻居是(a,b,c-1)。因此,当枚举点(a-1,b,c)时,点(a,b,c)已经在堆上;你甚至不需要检查它是否在那里。注意一些坐标相等的特殊情况。
此算法枚举球体,而不是立方体。很容易将注意力限制在具有最大索引D的立方体上。如果其中一个坐标等于D,则不要添加三个点,但要少一些。当没有更多有效的邻居点要添加时,枚举以点(D,D,D)结束。
此算法的性能应该非常快。它需要一个大小为O(N ^ 2)的堆。如果您事先枚举所有点,则需要存储O(N ^ 3)。此外,它不需要乘法,以进一步加速。
答案 4 :(得分:2)
如果它只是中心:有很多不同的有效订单。只需计算一个三维地图,按顺序排列元素。抵消原产地。制作地图:
for x,y,z -domain, domain
map.add ( x,y,z, distance(x,y,z) )
map.sort ( distance )
然后在点x,y,z遍历
for ( i=0; i++ )
visit ( map[i].xyz + x,y,z )
如果它是真正的距离而不是体素中心,则会变得更加困难。
答案 5 :(得分:2)
以 Manhatan距离顺序生成索引类似于子集和问题,因此只需计算最大距离(总和),然后分离轴以减少问题。这里 C ++ 示例:
int x,y,z,d,dx,dy,dz,D;
// center idx
int cx=n>>1;
int cy=n>>1;
int cz=n>>1;
// min idx
int x0=-cx;
int y0=-cy;
int z0=-cz;
// max idx
int x1=n-1-cx;
int y1=n-1-cy;
int z1=n-1-cz;
// max distance
x=max(x0,x1);
y=max(y0,y1);
z=max(z0,z1);
D=x+y+z;
// here do your stuff
#define traverse(x,y,z) { /* do something with the array beware x,y,z are signed !!! */ }
// traversal
for (d=0;d<=D;d++) // distance
for (dx=d ,x=-dx;x<=dx;x++) if ((x>=x0)&&(x<=x1)) // x axis separation
for (dy=d-abs(x) ,y=-dy;y<=dy;y++) if ((y>=y0)&&(y<=y1)) // y axis separation
{
dz=d-abs(x)-abs(y); // z axis have only 1 or 2 options
z=-dz; if (z>=z0) traverse(x,y,z);
z=+dz; if ((z)&&(z<=z1)) traverse(x,y,z);
}
#undef traverse
您可以使用您想要的任何内容或功能替换traverse(x,y,z)
宏。请注意x,y,z
已签名,因此您需要使用(x+cx,y+cy,z+cz)
来获取 C ++ 样式索引。
这可以处理booth偶数和奇数索引以及非立方体分辨率(如果你只是在前几个常量计算中将n
转换为nx,ny,nz
。 [0,0,0]
也可以在任何地方(不在中心),因此很容易适用于我能想到的任何需求......
此处为n=5
[ 0, 0, 0] = 0
[-1, 0, 0] = 1
[ 0,-1, 0] = 1
[ 0, 0,-1] = 1
[ 0, 0, 1] = 1
[ 0, 1, 0] = 1
[ 1, 0, 0] = 1
[-2, 0, 0] = 2
[-1,-1, 0] = 2
[-1, 0,-1] = 2
[-1, 0, 1] = 2
[-1, 1, 0] = 2
[ 0,-2, 0] = 2
[ 0,-1,-1] = 2
[ 0,-1, 1] = 2
[ 0, 0,-2] = 2
[ 0, 0, 2] = 2
[ 0, 1,-1] = 2
[ 0, 1, 1] = 2
[ 0, 2, 0] = 2
[ 1,-1, 0] = 2
[ 1, 0,-1] = 2
[ 1, 0, 1] = 2
[ 1, 1, 0] = 2
[ 2, 0, 0] = 2
[-2,-1, 0] = 3
[-2, 0,-1] = 3
[-2, 0, 1] = 3
[-2, 1, 0] = 3
[-1,-2, 0] = 3
[-1,-1,-1] = 3
[-1,-1, 1] = 3
[-1, 0,-2] = 3
[-1, 0, 2] = 3
[-1, 1,-1] = 3
[-1, 1, 1] = 3
[-1, 2, 0] = 3
[ 0,-2,-1] = 3
[ 0,-2, 1] = 3
[ 0,-1,-2] = 3
[ 0,-1, 2] = 3
[ 0, 1,-2] = 3
[ 0, 1, 2] = 3
[ 0, 2,-1] = 3
[ 0, 2, 1] = 3
[ 1,-2, 0] = 3
[ 1,-1,-1] = 3
[ 1,-1, 1] = 3
[ 1, 0,-2] = 3
[ 1, 0, 2] = 3
[ 1, 1,-1] = 3
[ 1, 1, 1] = 3
[ 1, 2, 0] = 3
[ 2,-1, 0] = 3
[ 2, 0,-1] = 3
[ 2, 0, 1] = 3
[ 2, 1, 0] = 3
[-2,-2, 0] = 4
[-2,-1,-1] = 4
[-2,-1, 1] = 4
[-2, 0,-2] = 4
[-2, 0, 2] = 4
[-2, 1,-1] = 4
[-2, 1, 1] = 4
[-2, 2, 0] = 4
[-1,-2,-1] = 4
[-1,-2, 1] = 4
[-1,-1,-2] = 4
[-1,-1, 2] = 4
[-1, 1,-2] = 4
[-1, 1, 2] = 4
[-1, 2,-1] = 4
[-1, 2, 1] = 4
[ 0,-2,-2] = 4
[ 0,-2, 2] = 4
[ 0, 2,-2] = 4
[ 0, 2, 2] = 4
[ 1,-2,-1] = 4
[ 1,-2, 1] = 4
[ 1,-1,-2] = 4
[ 1,-1, 2] = 4
[ 1, 1,-2] = 4
[ 1, 1, 2] = 4
[ 1, 2,-1] = 4
[ 1, 2, 1] = 4
[ 2,-2, 0] = 4
[ 2,-1,-1] = 4
[ 2,-1, 1] = 4
[ 2, 0,-2] = 4
[ 2, 0, 2] = 4
[ 2, 1,-1] = 4
[ 2, 1, 1] = 4
[ 2, 2, 0] = 4
[-2,-2,-1] = 5
[-2,-2, 1] = 5
[-2,-1,-2] = 5
[-2,-1, 2] = 5
[-2, 1,-2] = 5
[-2, 1, 2] = 5
[-2, 2,-1] = 5
[-2, 2, 1] = 5
[-1,-2,-2] = 5
[-1,-2, 2] = 5
[-1, 2,-2] = 5
[-1, 2, 2] = 5
[ 1,-2,-2] = 5
[ 1,-2, 2] = 5
[ 1, 2,-2] = 5
[ 1, 2, 2] = 5
[ 2,-2,-1] = 5
[ 2,-2, 1] = 5
[ 2,-1,-2] = 5
[ 2,-1, 2] = 5
[ 2, 1,-2] = 5
[ 2, 1, 2] = 5
[ 2, 2,-1] = 5
[ 2, 2, 1] = 5
[-2,-2,-2] = 6
[-2,-2, 2] = 6
[-2, 2,-2] = 6
[-2, 2, 2] = 6
[ 2,-2,-2] = 6
[ 2,-2, 2] = 6
[ 2, 2,-2] = 6
[ 2, 2, 2] = 6
答案 6 :(得分:1)
每个点(a, b, c)
都知道与原点的距离为sqrt(a*a + b*b + c*c)
。我们可以将其定义为distance(a, b, c)
。†
对于3D数组中的每个点,您可以使用distance
作为订购条件将其插入min heap。为避免重新计算,请在堆中扩充点表示,以便在插入堆时包含该点的distance
的缓存计算。
heap_element =(x,y,z,d)
heap_compare(heap_element a,heap_element b)= a.d&lt; b.d
对于3D阵列中的每个点(x,y,z) · heap.add(heap_element(x,y,z,distance(x,y,z)))
现在,您可以从堆顶部抽出每个点来获取订单。
N = heap.size
因为我在0..N
· ordered [i] = heap.top
· heap.pop
<子>
†出于本算法的目的,使用实际距离并不重要。出于性能原因,您可以省略sqrt
,并使用a*a + b*b + c*c
作为堆排序条件的度量标准。
子>
答案 7 :(得分:1)
在红宝石中,我只是按顺序从中心获得每个距离的所有点。
def get_points(side_len)
side_len % 2 == 0 ? min_dist = 1 : min_dist = 0
if side_len % 2 == 0
min_dist = 1
max_1d_dist = side_len / 2
else
min_dist = 0
max_1d_dist = (side_len - 1) / 2
end
max_dist = 3 * max_1d_dist
min_dist.upto(max_dist) do |dist|
min_x_dist = [min_dist, dist - 2 * max_1d_dist].max
max_x_dist = [dist - 2 * min_dist, max_1d_dist].min
min_x_dist.upto(max_x_dist) do |x_dist|
min_y_dist = [min_dist, dist - x_dist - max_1d_dist].max
max_y_dist = [dist - x_dist - min_dist, max_1d_dist].min
min_y_dist.upto(max_y_dist) do |y_dist|
z_dist = dist - x_dist - y_dist
print_vals(x_dist, y_dist, z_dist)
end
end
end
end
def print_vals(x_dist, y_dist, z_dist)
x_signs = [1]
y_signs = [1]
z_signs = [1]
x_signs << -1 unless x_dist == 0
y_signs << -1 unless y_dist == 0
z_signs << -1 unless z_dist == 0
x_signs.each do |x_sign|
y_signs.each do |y_sign|
z_signs.each do |z_sign|
puts "[#{x_sign*x_dist}, #{y_sign*y_dist}, #{z_sign*z_dist}]"
end
end
end
end
输出是:
2.1.2 :277 > get_points(1)
[0, 0, 0]
2.1.2 :278 > get_points(2)
[1, 1, 1]
[1, 1, -1]
[1, -1, 1]
[1, -1, -1]
[-1, 1, 1]
[-1, 1, -1]
[-1, -1, 1]
[-1, -1, -1]
2.1.2 :279 > get_points(3)
[0, 0, 0]
[0, 0, 1]
[0, 0, -1]
[0, 1, 0]
[0, -1, 0]
[1, 0, 0]
[-1, 0, 0]
[0, 1, 1]
[0, 1, -1]
[0, -1, 1]
[0, -1, -1]
[1, 0, 1]
[1, 0, -1]
[-1, 0, 1]
[-1, 0, -1]
[1, 1, 0]
[1, -1, 0]
[-1, 1, 0]
[-1, -1, 0]
[1, 1, 1]
[1, 1, -1]
[1, -1, 1]
[1, -1, -1]
[-1, 1, 1]
[-1, 1, -1]
[-1, -1, 1]
[-1, -1, -1]
答案 8 :(得分:0)
这是一种简单和快速算法,可以使用曼哈顿距离横切3D数组。
每个维度中大小为n
的3D数组应由坐标系表示,其原点位于数组的中间。对于要定义的中心,我们假设每个维度中的数组大小是奇数。每个元素都有一个三元坐标,如[x, y, z]
,每个坐标的最大值可以达到`(n / 2)-1。 (信息:添加的图片为2D以便更好地理解)
x+y+z=distance
的等式的平面定义。我们通过统一计算从0
到n-1
的距离来实现这一目标。对于每个距离,我们寻找相应平面上的所有元素。
distance>(n/2)-1
时,某些点将位于数组之外(coord > (n/2)-1
之一)。所以我们必须将它们排除在结果之外。
-1
来实现此目的。 [+/-x, +/-y, +/-z]
(如果全部为coords != 0
,则为8种可能的组合)
以下是我算法的代码架构:
//rise the distance by one each iteration
for(distance=0; distance<n-1; distance++) //loop distance from 0 to n-1
for(i=0; i<=distance; i++)
x=i; //x ∈ [0, distance]
for(j=0; j<=distance-x; j++)
y=j; //y ∈ [0, distance-x]
z=distance-(x+y); //because distance=x+y+z
//now we have to exclude all elements with one coord <= (n/2)-1
if(x<=(n/2)-1 && y<=(n/2)-1 && z<=(n/2)-1)
//[x,y,z] we found a valid element!
//let's generate the 7 corresponding elements (up to 7)
if(x!=0) //[-x,y,z]
if(y!=0) //[x,-y,z]
if(z!=0) //[x,y,-z]
if(x!=0 && y!=0) //[-x,-y,z]
if(x!=0 && z!=0) //[-x,y,-z]
if(y!=0 && z!=0) //[x,-y,-z]
if(y!=0 && y!=0 && z!=0) //[-x,-y,-z]
以下是n=7
的输出:
Distance:0 [0,0,0]
Distance:1 [0,0,1] [0,0,-1] [0,1,0] [0,-1,0] [1,0,0] [-1,0,0]
Distance:2 [0,0,2] [0,0,-2] [0,1,1] [0,-1,1] [0,1,-1] [0,-1,-1] [0,2,0] [0,-2,0] [1,0,1] [-1,0,1] [1,0,-1] [-1,0,-1] [1,1,0] [-1,1,0] [1,-1,0] [-1,-1,0] [2,0,0] [-2,0,0]
Distance:3 [0,1,2] [0,-1,2] [0,1,-2] [0,-1,-2] [0,2,1] [0,-2,1] [0,2,-1] [0,-2,-1] [1,0,2] [-1,0,2] [1,0,-2] [-1,0,-2] [1,1,1] [-1,1,1] [1,-1,1] [1,1,-1] [-1,-1,1] [-1,1,-1] [1,-1,-1] [-1,-1,-1] [1,2,0] [-1,2,0] [1,-2,0] [-1,-2,0] [2,0,1] [-2,0,1] [2,0,-1] [-2,0,-1] [2,1,0] [-2,1,0] [2,-1,0] [-2,-1,0]
Distance:4 [0,2,2] [0,-2,2] [0,2,-2] [0,-2,-2] [1,1,2] [-1,1,2] [1,-1,2] [1,1,-2] [-1,-1,2] [-1,1,-2] [1,-1,-2] [-1,-1,-2] [1,2,1] [-1,2,1] [1,-2,1] [1,2,-1] [-1,-2,1] [-1,2,-1] [1,-2,-1] [-1,-2,-1] [2,0,2] [-2,0,2] [2,0,-2] [-2,0,-2] [2,1,1] [-2,1,1] [2,-1,1] [2,1,-1] [-2,-1,1] [-2,1,-1] [2,-1,-1] [-2,-1,-1] [2,2,0] [-2,2,0] [2,-2,0] [-2,-2,0]
Distance:5 [1,2,2] [-1,2,2] [1,-2,2] [1,2,-2] [-1,-2,2] [-1,2,-2] [1,-2,-2] [-1,-2,-2] [2,1,2] [-2,1,2] [2,-1,2] [2,1,-2] [-2,-1,2] [-2,1,-2] [2,-1,-2] [-2,-1,-2] [2,2,1] [-2,2,1] [2,-2,1] [2,2,-1] [-2,-2,1] [-2,2,-1] [2,-2,-1]
如果你使用欧几里得规范,你必须用sqrt(x*x+y*y+z*z)
替换你的距离,你不能以一步为单位增加距离。但除此之外你可以非常相似。
答案 9 :(得分:0)
等到赏金比赛结束,不要干涉。但是我想指出,我能看到的所有答案非常可疑。这个问题有这样的说法:
&#34;此算法适用于 GPU &#34;
确实可以在GPU上进行有效的数字处理,但是这里的所有解决方案都提出了某种循环。这> 不是GPU如何工作。
GPU并行执行。事实上,人们可以在GPU中循环,但随后它以极其孤立的方式发生。循环需要一个&#34;全局控制器&#34;,例如一个计数器,但GPU执行的重点是它使用多个核以无特定顺序执行。抓住&#34;是不可能的。一个核心的结果&#39;执行并将其用作另一个核心的参数。计算。这根本不是GPU的工作原理。
可以在GPU上计算多维数组,即使在高于3维的情况下也是如此。这只是单元寻址的问题,并且使用一维地址空间解决例如4维度并描述/访问相应数据是微不足道的。
但不可能以特定的顺序逐个遍历单元格(像素,内存位置) - 对此无法控制。并且不可能增加,或具有循环,或具有内部循环。在GPU上,最后一个元素可能首先被执行。在GPU上,每个元素都完全自主。没有计算知道任何其他计算,因为它们之间没有通信。 GPU上每次计算的环境都是,如果它在世界上一个人。
此主题中给出的答案均假设 CPU 逻辑。如果解决CPU上的问题,这是微不足道的。以二维为例,这里是5x5的绝对x,y坐标对,在中间调整为零:
┌───┬───┬───┬───┬───┐
│2 2│2 1│2 0│2 1│2 2│
├───┼───┼───┼───┼───┤
│1 2│1 1│1 0│1 1│1 2│
├───┼───┼───┼───┼───┤
│0 2│0 1│0 0│0 1│0 2│
├───┼───┼───┼───┼───┤
│1 2│1 1│1 0│1 1│1 2│
├───┼───┼───┼───┼───┤
│2 2│2 1│2 0│2 1│2 2│
└───┴───┴───┴───┴───┘
在每个单元格中添加对可以得到曼哈顿距离:
4 3 2 3 4
3 2 1 2 3
2 1 0 1 2
3 2 1 2 3
4 3 2 3 4
与此同时,我们可以建立一个索引系统(但这是一个问题的弱点,因为它没有状态地址空间):
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25
我们可以平息两个距离:
dist = 4 3 2 3 4 3 2 1 2 3 2 1 0 1 2 3 2 1 2 3 4 3 2 3 4
和索引
index = 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
N(或N * N或N * N * N)阵列的唯一曼哈顿距离如果N为奇数,则1和N-1之间的所有数字都先于0。对于5 * 5矩阵:
0 1 2 3 4
走过每个距离,看看距离等于&#34; dist&#34;。对于5 * 5:
0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 // dist = 0 at locations 13
0 0 0 0 0 0 0 1 0 0 0 1 0 1 0 0 0 1 0 0 0 0 0 0 0 // dist = 1 at locations 8 12 14 18
0 0 1 0 0 0 1 0 1 0 1 0 0 0 1 0 1 0 1 0 0 0 1 0 0 // dist = 2 at locations 3 7 9 11 15 17 19 23
0 1 0 1 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 1 0 1 0 // dist = 3 at locations 2 4 6 10 16 20 22 24
1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 // dist = 4 at locations 1 5 21 25
并根据这些位置构建一个数组。 IE浏览器。有一个ampty数组,作为它的第一个元素追加13,然后追加8 12 14 18,等等。最终的结果将是
13 8 12 14 18 3 7 9 11 15 17 19 23 2 4 6 10 16 20 22 24 1 5 21 25
这是所需的顺序。通过使用除法,分钟和残差,可以很容易地将其重新排列到例如二维地址空间中。
但是,这种计算方法是GPU上的USELESS。它需要一个特定的执行顺序,而我们没有GPU 。
如果在GPU上解决遍历顺序,解决方案应该是
lookupcoordinates = fn(currentposition)
有可能描述fn,但问题太不完整了 - 需要更多细节,而不仅仅是在GPU&#34;上说&#34;。如何描述3d数组?它在什么记忆中?结果的广告空间是什么?等等。
我很高兴听到更多有关此问题的详细信息,以及对上述内容的更正。
与用户m69进行讨论的附录
一个(次要的)思想是在[维数]步骤中进行计算,其中来自先前维度的累积将用于下一个,直到例如3.可能数值行为在这样的情况下是有用的。一个案例。
如果仔细观察基础知识,人们可能会假设一个线性目标空间,这样它就是一个从1到[单元格数]的简单索引向量,例如10 * 10 * 10立方体就具有线性1000个索引的1D向量,从1到1000.以后总是可以将这些索引重新标记为方形或更多维格式。
在一维情况下,让我们假设我们有一个9元素数据&#34; cube&#34; (与9 * 1 * 1相同,如果是三维表示的话)。如下所示
x x x x x x x x x // Data
1 2 3 4 5 6 7 8 9 // Indexes
4 3 2 1 0 1 2 3 4 // Manhattan distances
5 4 6 3 7 2 8 1 9 // Pick order, starting from center
因此我们需要一个 fn ,其映射如下
┌──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┐
│1 to 5│2 to 4│3 to 6│4 to 3│5 to 7│6 to 2│7 to 8│8 to 1│9 to 9│
└──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┘
现在,如果查看结果的索引4,fn必须能够独立于任何其他索引解析结果= 3,即。 fn(4)= 3 。应该可以描述fn。应该可以首先得出结论:&#34; 4&#34;驻留在第2层(如果第0层是最里面的)。在那之后,应该可以得出结晶2的多样性细胞层(所有层有2个细胞),最后是否该细胞是第2层的第一个或第二个出现/元素。那将解析为3,即。对于结果[4],我们选择数据[3]。
现在,如果假设一个二维&#34;立方体&#34;大小为11 * 11(* 1),我们有这种情况:
0 1 2 3 4 5 6 7 8 9 10 // Unique Manhattan distances
1 4 8 12 16 20 20 16 12 8 4 // How many cells in each distance-layer?
我们注意到&#34;多少&#34;是相对对称的,对于10 * 10来说更加对称:
1 2 3 4 5 6 7 8 9 // Unique Manhattan distances
4 8 12 16 20 16 12 8 4 // How many cells in each distance-layer?
4 12 24 40 60 76 88 96 100 // Cumulative sum of "How many..."
注意&#34;累积金额&#34;!使用它,如果我们正在解决例如index = 55(可以在54之前或之后的任何时间发生,请记住!),我们可以得出结论,我们目前的目标是第5层,它包含20个元素,那些具有index = 40 ... 60。
这一层以40开头,我们现在为55.差异为15.也许可以描述偏移(x,y) - 来自&#34;第5层的坐标起源x,y)使用&#34; 15&#34;?我的猜测是我们刚进入第四象限。
3D相同吗?