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内的相邻敌人数量
    • 按其邻居的数量降序排列敌人
    • 检查敌人名单,开始