Google Code Jam长城问题是否有更快的解决方案


16

考虑以下Google Code Jam回合1C问题

中国的长城始于一条无限的线,所有位置的高度均为。0

一些部落,会根据以下参数攻击墙壁:开始日,开始强度,开始西坐标和开始东坐标。这第一次攻击发生在一天,上范围,在强度。如果中有长城的任何部分的高度,则攻击成功,并且在一天结束时,将建造长城,以使其在高度会处于高度Ñ 1000 d 小号W¯¯ é d [ w ^ ë ] 小号[ w ^ ë ] < 小号[ w ^ ë ] < 小号小号NN1000DSWED[W,E]S[W,E]<S[W,E]<SS(或更大,如果当天其他一些攻击以强度击中同一段)S>S

每个部落在撤退之前将进行多达攻击,并且每次攻击都将根据之前的迭代来确定。每个部落都有一些,和\ delta_S来确定攻击顺序:两次攻击之间将等待\ delta_D \ ge 1天,对于每次攻击,他们将移动其攻击范围\ delta_X单位(负=西,正=东部),但范围的大小将保持不变,并且每次攻击后它们的强度也会以恒定值增加/减少。δ d δ X δ 小号δ d1 δ X1000δDδXδSδD1δX

该问题的目的是,在对攻击部落有完整描述的情况下,确定成功攻击多少次。

我设法编写了一个有效的解决方案,可以在20秒钟内运行:我相信我实施的解决方案需要O(AlogA+(A+X)logX)时间,其中A=受到攻击的总数模拟(最大1000000),X=攻击范围内唯一边缘点的总数(最大2000000)。

从高层次来看,我的解决方案是:

  • 读取所有部落信息
  • 计算攻击范围的所有唯一X坐标O(A)
  • 将Wall表示为范围上的延迟更新的二叉树,该树跟踪最小高度值。叶是两个坐标的跨度,中间没有任何东西,所有父节点代表其子级所覆盖的连续间隔。-XXO(XlogX)
  • 生成每个部落将执行的所有攻击,并按天对它们进行排序O(AlogA)
  • 对于每次攻击,请查看攻击是否成功(查询时间)。当日期改变时,遍历所有未处理的成功攻击并相应地更新隔离墙(每次攻击的更新时间)。-logXlogXO(AlogX)

我的问题是:是否有比更好的方法?也许,是否有某种战略方法可以利用部落的连续攻击的线性性质?20秒钟的时间对于预期的解决方案来说太长了(尽管Java可能是造成这种情况的原因)。O(AlogA+(A+X)logX)


3
请不要关闭它。这是一个有效的问题。答案将是一个下界证明,表明如果做的确实是我们可以做到的最好,我们就无法做得更好。例如,我猜测我们也许可以在这里使用“元素差异问题”,但还没有时间考虑它。
Aryabhata

然后,我将其保持打开状态:)
扭矩冲击

Answers:


2

显而易见的改进空间是此步骤:

生成每个部落将执行的所有攻击,并按天对它们进行排序O(AlogA)

我们知道,部落将从特定的一天开始定期发起攻击。这意味着我们实质上应该合并许多预先排序的列表。问题陈述还告诉我们,部落永远不会超过1000个(即合并的1000个列表);与1,000,000次最大攻击相比,这是一个很小的数目!根据实现的相对时间,切换此设置可以将处理时间减少一半。

我实际上可以建议优化理论上的复杂性,但是我没有证据表明在进行此更改后它会是最佳的。


我自己给难题打了个谜,但我使用了墙壁的许多暗色表示法:二叉搜索树(std::map准确地说是C ++ )存储墙壁高度变化的位置。这样,我便能够根据需要添加和删除节点(即,如果一个复杂的部分遭受到巨大的压倒性攻击,或者碰到相同强度的多次攻击,则节点数将大大减少)。这解决了3.9秒内的大量输入(在我的中等规格开发笔记本电脑上)。我怀疑有改善的原因有几个:

  • 正如您所指出的那样,装箱和拆箱可能会变得很昂贵,但是C ++基于模板的容器完全避免了这种情况。
  • 尽管我使用的墙表示在理论上更糟,但是在大多数情况下,能够动态减少节点的数量使其变得超快(大多数测试用例在1k个节点以下达到最大值,而除2个以外的所有情况都在10k以下) 。实际上,唯一花费大量时间的情况是#7,它似乎在测试许多非相交的范围。
  • 我没有进行任何预处理(阶段是通过跟踪每个部落下一次进攻的时间,并在每回合中搜索最低的关节来确定的)。从理论上讲,这再一次变得更糟,但是对于大多数情况,我怀疑开销较低意味着它更快(我将对其进行测试并与您联系)。 更新:我添加了一个用于攻击的优先级队列,类似于上述方法(尽管不是动态创建大型数组,而是即时计算出来的),并且看到大型输入的时间减少到3.0秒。

简而言之,虽然我认为您的算法在一般情况下接近最佳,但是有几种方法可以加快典型输入的速度。


1

以下内容已删除,因为它是答案。

查看其他讨论和成功的解决方案似乎表明,我描述的解决方案几乎是预期的算法。我的解决方案变慢的原因可能是由于自动装箱和基于指针的树结构的延迟使用,而不是基于数组的结构的延迟-因此,我怀疑,如果确实存在一种解决方案,则可能不是一个整体比这里的要好得多。

解决方案可以在这里找到。它与我在此处发布的内容几乎相同;因此我更倾向于认为不存在更有效的解决方案。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.