我正在寻找一种枚举算法来搜索围绕给定起点的3D数组“sphering”。
给定大小为a
的数组NxNxN
,其中N
对于某些2^k
为k
,并且该数组中有p
个点a[p]
。我正在寻找的算法应该执行以下操作:如果p
满足某个谓词,算法将停止并返回q
。否则,将检查下一个点q
,其中p
是数组中距离q'
最近且尚未访问过的另一个点。如果两者都不匹配,则检查下一个q
,直到最坏的情况下搜索整个数组。
通过“最接近”这里,完美的解决方案是与p
具有最小欧几里德距离的点public static void main(String[] argv) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.FANOUT);
String message = getMessage(argv);
channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes("UTF-8"));
System.out.println(" [x] Sent '" + message + "'");
channel.close();
connection.close();
}
。由于只需要考虑离散点,也许一些聪明的枚举算法可以使这成为可能。但是,如果这太复杂,曼哈顿最小的距离也会很好。如果有几个最近的点,那么接下来应该考虑哪一个并不重要。
是否已有可用于此任务的算法?
答案 0 :(得分:1)
这是一个简单算法的伪代码,它将在增加半径的球形外壳中搜索,直到它找到一个点或者它用完了数组。让我们假设condition
返回true或false并且可以访问正在测试的x,y,z坐标和数组本身,为越界坐标返回false(而不是爆炸):
def find_from_center(center, max_radius, condition) returns a point
let radius = 0
while radius < max_radius,
let point = find_in_spherical_husk(center, radius, condition)
if (point != null) return point
radius ++
return null
困难部分在find_in_spherical_husk
内。我们有兴趣查看点
dist(center, p) >= radius AND dist(center, p) < radius+1
这将是我们对稻壳的操作定义。我们可以在O(n ^ 3)中迭代整个3D数组来寻找那些,但这在时间上会非常昂贵。一个更好的伪代码如下:
def find_in_spherical_husk(center, radius, condition)
let z = center.z - radius // current slice height
let r = 0 // current circle radius; maxes at equator, then decreases
while z <= center + radius,
let z_center = (z, center.x, point.y)
let point = find_in_z_circle(z_center, r)
if (point != null) return point
// prepare for next z-sliced cirle
z ++
r = sqrt(radius*radius - (z-center.z)*(z-center.z))
这里的想法是将每个外壳切成沿z轴的圆圈(任何轴都可以),然后分别查看每个切片。如果你正在看地球,而极点是z轴,那么你将从北向南切割。最后,您将实施find_in_z_circle(z_center, r, condition)
来查看每个圈子的周长。你可以使用Bresenham circle-drawing algorithm来避免一些数学运算;但我认为与检查condition
的费用相比,节省的费用可以忽略不计。
答案 1 :(得分:1)
您可以搜索增加的平方距离,这样您就不会错过一个点。这个python代码应该清楚说明:
import math
import itertools
# Calculates all points at a certain distance.
# Coordinate constraint: z <= y <= x
def get_points_at_squared_euclidean_distance(d):
result = []
x = int(math.floor(math.sqrt(d)))
while 0 <= x:
y = x
while 0 <= y:
target = d - x*x - y*y
lower = 0
upper = y + 1
while lower < upper:
middle = (lower + upper) / 2
current = middle * middle
if current == target:
result.append((x, y, middle))
break
if current < target:
lower = middle + 1
else:
upper = middle
y -= 1
x -= 1
return result
# Creates all possible reflections of a point
def get_point_reflections(point):
result = set()
for p in itertools.permutations(point):
for n in range(8):
result.add((
p[0] * (1 if n % 8 < 4 else -1),
p[1] * (1 if n % 4 < 2 else -1),
p[2] * (1 if n % 2 < 1 else -1),
))
return sorted(result)
# Enumerates all points around a center, in increasing distance
def get_next_point_near(center):
d = 0
points_at_d = []
while True:
while not points_at_d:
d += 1
points_at_d = get_points_at_squared_euclidean_distance(d)
point = points_at_d.pop()
for reflection in get_point_reflections(point):
yield (
center[0] + reflection[0],
center[1] + reflection[1],
center[2] + reflection[2],
)
# The function you asked for
def get_nearest_point(center, predicate):
for point in get_next_point_near(center):
if predicate(point):
return point
# Example usage
print get_nearest_point((1,2,3), lambda p: sum(p) == 10)
基本上你从生成器消耗点,直到其中一个点满足你的谓词。