Algorithm 如何快速找到最佳投弹区?
我的家庭作业是这样的: 您将看到一幅由四种颜色的像素组成的图像。颜色对应于地形、敌人、盟友和城墙。炸弹可以投到任何坐标(一对整数)。你还可以得到:Algorithm 如何快速找到最佳投弹区?,algorithm,language-agnostic,Algorithm,Language Agnostic,我的家庭作业是这样的: 您将看到一幅由四种颜色的像素组成的图像。颜色对应于地形、敌人、盟友和城墙。炸弹可以投到任何坐标(一对整数)。你还可以得到: r-炸弹的作用半径(以像素为单位,正整数) e-杀死敌人的点数 a-杀死盟友的点数 (例如r=10,e=1,a=-2) 投下炸弹时,半径(欧几里德距离)内的所有敌人和盟友都将被杀死,除非他们和炸弹之间有一堵墙(即连接士兵和炸弹的非抗锯齿线穿过一堵墙)。当炸弹落在墙上时,该特定像素的行为与普通地形类似。墙的其余部分仍然是一堵墙 你以0分开始。找到你
-炸弹的作用半径(以像素为单位,正整数)r
-杀死敌人的点数e
-杀死盟友的点数a
r=10
,e=1
,a=-2
)
投下炸弹时,半径(欧几里德距离)内的所有敌人和盟友都将被杀死,除非他们和炸弹之间有一堵墙(即连接士兵和炸弹的非抗锯齿线穿过一堵墙)。当炸弹落在墙上时,该特定像素的行为与普通地形类似。墙的其余部分仍然是一堵墙
你以0分开始。找到你应该投一颗炸弹的坐标,以获得尽可能好的分数。如果存在多个最佳解决方案,请返回其中任何一个
下面是一个裁剪、调整大小并更改颜色以提高可读性的示例图像:
我得到的原始图像可以找到
我已经做了什么
我知道用暴力强迫解决这个问题是一个可怕的解决办法。我想出了一个主意,在没有围墙的情况下如何快速解决它。下面是一些伪代码:
args Map, R, A, E
for (every Soldier)
create a Heightmap with dimensions of Map
zero-fill the Heightmap
on the Heightmap draw a filled circle of value 1 around Soldier with radius R
if (Soldier is Ally)
multiply Heightmap by A
else
multiply Heightmap by E
add all Heightmaps together
return coordinates of highest point in TotalHeightmap
当然,这个“片段”可以优化,但在这种形式下更容易理解。通过使用墙约束heightmap圆,可以将其扩展为完整的解决方案。绘制圆很简单,许多图像处理库都提供了这样做的功能,因此最好先绘制圆,然后在圆上绘制墙,然后从墙或圆边界的中心开始填充圆。我将在实施时检查性能
在不限制圆圈的情况下,我会这样做:
run the above code to get a TotalHeightmap
create empty PointList
for (every Point in TotalHeightmap)
create PointObject with properties:
Coordinates,
Height,
WallsFlag = False
add PointObject to PointList
sort PointList by descending Height
until (PointList[0].WallsFlag == True)
for (every Soldier in radius R from PointList[0])
if (Bresenham line connecting Soldier with PointList[0] intersects a Wall)
subtract (A if Soldier is Ally else E) from PointList[0].Height
set PointList[0].WallsFlag = True
sort PointList by descending Height
return PointList[0].Coordinates
只要敌人和盟友的分数都是非负的,它就会起作用,所以它远不是完美的。为了解决这个问题,我可以在所有像素上循环,但这会非常慢(我想不会像暴力强迫那样慢,但听起来不是个好主意)。寻找墙交点的方法似乎也很粗糙
我正在寻找一个更优雅、更快速的解决方案。你将如何解决它?如果有帮助的话,我将用Python和PIL实现它
顺便说一句,我相信我的老师会同意我把这个问题贴在上面,所以,我相信他甚至希望我讨论这个问题,并实施最佳解决方案
这里有一个部分答案,我希望能引起一些讨论: 解决任何问题的第一条规则是找到一个更容易的问题。在这种情况下,我们可以问: 如果没有墙,什么是好的解决方案 并进一步降低到 如果没有围墙或敌人,什么是好的解决方案 更进一步说, 如果没有围墙或敌人,并且炸弹的半径为1,那么什么是好的解决方案 这相当于说 给定一组点,定位一个单元盘以覆盖尽可能多的点 酷。这感觉像是一个很好的、可靠的、独立于领域的问题,很多人以前肯定遇到过。通过谷歌快速搜索,我们找到了很多相关资源,包括 在这个问题上,公认的答案提供了一个重要的观察结果:如果我们有一个覆盖最大点数的磁盘,我们可以移动该磁盘以获得另一个边缘上至少有两点的磁盘。同样地,如果我们取彼此距离2内的每一对点,并通过这对点构造两个单位圆(对于O(n^2)个圆),那么这些圆中的一个保证包含尽可能多的点 这可以很容易地适应您的问题的“无墙”版本。虽然它将是O(n^3)(可能是O(n^2)个圆,每个圆内可能有n个点),但它可能比典型问题实例中的速度快得多。如果你想聪明一点的话,可以研究一下固定半径最近邻问题(我能找到的最好的论文是,但不幸的是,没有公开的版本) 我们如何才能引入墙呢?如果磁盘与墙相交,我们无法可靠地移动它,使两个点位于边缘,同时保持相同的分数。我会考虑一下,希望其他人也会有一些想法 对任何候选算法进行心理测试的三种场景:
我认为你自己建议的算法是一个很好的方法:
- 对于每个敌人/盟友,用给定的墙画出目标可能被炸弹击中的所有位置的部分模糊圆圈
- 将所有这些圆圈与其各自的敌人/盟友成本累积在一起,得分最高的像素就是您的解决方案
- 将敌军目标存储在快速空间数据结构中,如KD树
- 对于每个敌人,找出距离2*r内的相邻敌人数量
- 按其邻居的数量降序排列敌人
- 检查敌人名单,开始