数字线上的访问点,同时将与距离无关的成本最小化


18

我需要有关此ACM ICPC问题的帮助。我目前的想法是将此模型建模为最短路径问题,在问题说明中对此进行了描述。

问题

除了以外,N = 1000沿一维数字线位于不同位置的有核废料容器。一个人的任务是收集所有垃圾箱。垃圾容器每秒钟收集一次,就会发出1单位的辐射。人开始时可以每秒移动一次,收集废物所花费的时间可以忽略不计。我们希望找到收集所有容器时释放的最小辐射量。-500,000 to 500,000x=0x = 01

输入样例:

4位于的集装箱[-12, -2, 3, 7]

收集这些容器的最佳顺序是[-2, 3, 7, -12],以减少50单位散发。说明:该人-2在2秒钟内进入,在此期间2 units辐射被发射。然后,他到达3(距离:),5以便枪管释放2 + 5 = 7出辐射单位。他需要4更多的时间才能到达x = 7那个发射桶的地方2 + 5 + 4 = 11。他花了19几秒钟到达x = -12那个桶发射2 + 5 + 4 + 19 = 30单位的地方。2 + 7 + 11 + 30 = 50,这就是答案。

笔记

有一个明显的O(N!)解决方案。但是,我研究了贪婪的方法,例如移到最近的方法,或移到最近的聚类方法,但是这些方法没有用。

我考虑了这个问题已经有一段时间了,并且已经将其建模为图形搜索问题:

  1. 我们插入 0作为基准位置(这将是初始状态)
  2. 然后,我们将位置从最小到最大排序。
  3. 然后,我们执行BFS / PFS,其中 state包括
    • 两个整数lr它们代表我们已经访问过的排序位置数组中的连续范围
    • 一个整数 loc,告诉我们我们是在范围的左侧还是右侧
    • 一个整数 time告诉我们经过时间
    • 整数“成本”,告诉我们到目前为止的总成本(基于我们访问过的节点)
  4. 从每个状态我们可以移至[l-1,r]和[l,r + 1],相应地调整其他3个整数
  5. 最终状态为[0,N],检查两个结束位置。

但是,似乎[L, R, loc]并不能唯一地定义状态,因此我们必须存储L, R, loc, and time,同时最小化cost每个状态。这导致了指数算法,对于任何优点来说仍然太慢了。

谁能帮助我扩展我的想法或将我推向正确的方向?

编辑:也许可以将其建模为动态编程优化问题?考虑它,它与图形搜索解决方案具有相同的问题-仅仅因为电流cost很低并不意味着它是该子问题的最佳答案,因为后者time也会极大地影响答案。

贪婪不起作用:我有一个贪婪的选择算法,该算法估算移动到特定位置的成本(例如,如果我们向右移动,我们到左桶的距离加倍,等等)。

您可以使用启发式方法进行优先级优先搜索吗?该启发式方法可以将当前行程的成本与经过的时间相结合。


最短路径算法怎么样?像Dijkstra的算法一样?
suraj_fale 2013年

我尝试过,但是我认为我做错了什么。我在底部附近用编号列表描述了我的算法(即优先优先搜索或BFS)。
Barron W.


抱歉,我看不到这两个问题之间的关系。你可以解释吗?
巴伦

2
这是ACM ICPC的实践问题,而不是现实生活中的问题。另一方面,我尝试降低状态但无济于事。我尝试编写DP解决方案,但是那也不起作用。状态为L,R,POS。
巴伦

Answers:


4

我认为您可以通过将问题看作是成对的有向图来改善此问题。

在此示例中,我将使用值为-9,-6,-1、3和5的行。

因为仅用文本绘制图形太困难了,所以我将这些对表示为表格。我们可以将这些单元视为代表已收集这两个位置之间的所有容器的状态。每个单元格都有两个值,一个代表左移的成本,另一个代表右移(到达下一个容器)的成本。

可以简单地将这些值计算为两个点之间的距离乘以这两个点之外的桶数+ 1。两个数字都具有相同符号的单元格代表已收集所有具有相反符号的桶的情况。这些仅使用远离零的方向上的发条盒数来计算。

在表中,值X表示您无法朝该方向前进(该方向上的所有枪管都已取走)。行代表收集器的当前位置,列代表下一个相对的枪管的位置。

    +------+------+------+------+------+
    |  -9  |  -6  |  -1  |   3  |   5  |
+---+------+------+------+------+------+
|-9 |      |      |      | X, 24| X, 14|
+---+------+------+------+------+------+
|-6 | 3, X |      |      | 9, 27| 6, 22|
+---+------+------+------+------+------+
|-1 |      |10, X |      |20, 8 |15, 18|
+---+------+------+------+------+------+
| 3 |24, 4 |27, 6 |16, 8 |      | X, 2 |
+---+------+------+------+------+------+
| 5 |14, X |22, X |18, X |      |      |
+---+------+------+------+------+------+

在正方形之间移动的规则可能会有些混乱。

对于负数列,规则如下:

  • 向右移动一个单元格。
  • 向左移动一个单元格,然后在对角线上镜像。
  • 如果右值为X,则向左移动到对角线(列和行相等),然后向左移动一。

对于正数列,规则如下:

  • 向左移动一个单元格。
  • 向右移动一个单元格,然后在对角线上镜像。
  • 如果左值为X,则向右移动将向下移动到对角线,然后右移一个。

现在,我们可以运行Dijkstra的算法来计算最佳路径,并使用这些运动规则遍历图形。我们的起始位置是(-1,3)和(3,-1),初始成本分别为5和15。一旦我们计算了两个终点位置((-9,-9的左侧)和(5,5)的右侧)的值,则两者中较小的一个就是我们的答案。

每个步骤的运行时间为:

  • O(N log N)用于最初沿线对输入值进行排序
  • O(N ^ 2)用于计算表格/图形
  • O(N ^ 2 log N)用于在图上运行Dijkstra(注意:任何给定的顶点最多有两个边)。

前两个步骤由最后一个步骤主导,因此您的总体运行时间为O(N ^ 2 log N),这应该足以应对挑战。


1

最短距离

我昨天写了一个Java应用程序来解决这个问题。正如SRJ在评论中所说,该问题基本上是最短距离问题。辐射仅表明您可以累积最短距离的值。

基本上,这就是我所做的。

  • 将容器编号放入List <Integer>
  • 虽然列表包含元素;
    • 查找最接近的元素
    • 如果有一个元素,请走到那里并删除该元素。
    • 如果有两个元素,请复制路径并步行至两个元素
  • 找到辐射值最小的路径。

这是应用程序的一些输出

10 containers are located at [-90, -75, -47, -9, 9, 26, 48, 50, 64, 79].

You walk to position -9 and pick up the container.  The total radiation emitted is 90 units.
You walk to position 9 and pick up the container.  The total radiation emitted is 252 units.
You walk to position 26 and pick up the container.  The total radiation emitted is 388 units.
You walk to position 48 and pick up the container.  The total radiation emitted is 542 units.
You walk to position 50 and pick up the container.  The total radiation emitted is 554 units.
You walk to position 64 and pick up the container.  The total radiation emitted is 624 units.
You walk to position 79 and pick up the container.  The total radiation emitted is 684 units.
You walk to position -47 and pick up the container.  The total radiation emitted is 1,062 units.
You walk to position -75 and pick up the container.  The total radiation emitted is 1,118 units.
You walk to position -90 and pick up the container.  The total radiation emitted is 1,133 units.

我没有以任何方式优化算法。我什至没有注意到输入的数字列表已经排序。(我是疯子。)

当我以最大值,1,000个容器和从-500,000到500,000的范围运行代码时,我的代码执行了3秒钟。大部分时间是在控制台上写入1,000条打印行。

我不是O的大人物,但我认为走最短路径算法的蛮力是O(N平方),而不是O(N!)。

如果我利用输入数字已排序的事实,从而只需要检查当前所在位置的两侧的两个数字,就可以使应用程序接近O(N)。我只需要检查2个数字,因为我在到达列表时要从列表中删除它们。

您使用了诸如贪婪算法之类的不同算法来找到近似解。

如果我的程序花了3个小时而不是3秒钟来运行,那么您将可以选择。

足够好的解决方案是否足够好?

换句话说,我是否愿意以处理速度来换取足够好的答案?

如果足够好的答案也足够好,则可以使用近似算法。

如果您想要一个完美的答案,则必须走所有最短的路径。没有捷径。

如果有人要我发布我的代码,我会的。我确定仍然存在错误,因为我想看看是否可以实现最短步行算法。


1

我有一个可以2^N及时解决此问题的解决方案,虽然效果不佳,但是我认为这是解决问题的一种有用方法,因此我想发表一下。

与其将问题建模为图形,不如将其建模为二进制决策树(例如T)。在每个级别,您都必须在向右或向左移动之间进行选择。计算每个边的“成本”非常容易。让h(K)是当前节点的高度K,那么边的成本要left_child(K) = h(K) x dist(K, left_child(K))。类似的计算足以满足右边孩子的边缘成本。您构造这棵树,并一直跟踪边缘的累积成本,并以最小的总成本向叶节点报告路径。

请注意,成本计算之所以有效,是因为每个边的长度dist(K, left_child(K))代表到达下一个站点的时间,而子树的高度是剩余站点的数量(例如仍在发射辐射)。

现在,此框架内的技巧是确定是否可以使用一些启发式方法来“证明”可以忽略沿某个分支扩展搜索。我的直觉是,对于任何这种启发式方法,都有一定的站点可以击败它,但是也许有人可以提出一些建议。

许多人提议为图形应用最短路径解决方案,我对这样的解决方案是否可以工作表示怀疑。问题中“图形”中的邻居会根据您选择的路径而变化。例如,在你原来的职位有[-12, -2, 3, 7],如果你去-2,然后-123成为“邻居”,如果你去3,然后-27是邻居。在最终图中,每个可能的正对和负对的“对”可能都是neigbhours。我不知道在动态图中可证明正确的最短路径算法。


0

我认为将每个阶段简单地看作是在转到最近的桶和转到最近的桶之间的二元选择是最有意义的。只需具有一个成本函数,该函数详细说明通过进行任何运动并选择成本最低的辐射单元,总共将产生的辐射单元数。

不要简单地考虑最近的枪管,而要假设远离枪管,您实际上是在增加两倍的辐射,因为通过移开枪管,您还需要稍后再返回该方向。

在[-12,-2,3,7]的示例中,向左移动将导致左侧总共14(2 + 2 + 10),向右产生18(2 + 2 + 5 + 9),总共22个。向右移动将在右侧产生10(3 + 3 + 4),在右侧产生26(3 + 3 + 5 + 15)。显然,最开始的时候左边是正确的解决方案。可以为每个连续的运动进行类似的计算。

之后,问题基本上减少到了搜索,因此复杂度应为O(nlog(n)),比O(n!)好得多。我认为这肯定是该问题可能存在的最低复杂度,因为它基本上是一种基于比较的搜索算法,对于该算法,不可能做得比O(nlog(n))更好。

显然我对这个描述不够清楚,因此我决定使其更具编程性:1.根据当前位置计算左转产生的成本,以及右移产生的成本2.移入最便宜的方向3.计算方向移动的成本时,不考虑到达的桶

计算成本:1.确定给定方向上最接近的枪管。假设$ dist是从当前位置到给定方向上最近的桶的距离。2.成本初始化为N * $ dist,其中N仅考虑仍处于活动状态的桶。3.为此,加上距离$ dist表示的新位置与剩余的每个桶的距离。


1
这并不总是有效。也许您可以对坐标进行排序,然后在状态包含范围[i..j](表示您访问过的范围),成本和当前时间的地方进行搜索。
巴伦W.13年

什么时候不起作用?
Slater Victoroff

有一个简单的测试用例失败了。我会尽力找到它,但它是用N = 4或5
巴隆W.

[43, -18, -98, -82, 63]
巴伦W.13年

也有类似的情况[-10,-11, 10,20,30,40,50,60,70]。正确且唯一的解决方案是收集所有负面的信息,然后收集正面的信息。对于455的一个答案
巴隆W.

0

部分解决方案-稍后再讨论。

假设“默认”策略一直向左或向右运行,以较便宜的一个为准。现在问,用另一种方式来捡起一个桶是否值得进行一次侧程旅行?计算答案相当容易。

对于您的输入样本,一直运行要比一直运行便宜。去-2值得一游吗?它将完全运行然后再降为0的成本降低了14(因为在默认策略下,您从0到3每次移动支付4个辐射单位,现在降至3,从3支付3。到7,现在是2,依此类推),再加上每移动一次,您从0到-2的移动成本降低了,因此又节省了2,总共减少了16。

但是,它增加了成本,即从-2再回到14中的0(每移动4个单位到-2,每3个单位回到0),得到的净收益为(16-14)= 2。请注意,计算此费用时,您不必为每个决策评估解决整个问题的确切成本-您有足够的信息来决定,只需知道一路顺行比一路顺行便宜,再加上如何您的每一边都有许多废品容器,而到最近的容器中有2个容器。这就是O(N ^ 2)。

除了一个重要的问题-我假设您将一直运行到最后,我们知道您可能会加倍努力。要清理,我们需要更新我的计算。对于样本输入,我假设通过从0到7往返运行,每单位每秒发射的总辐射少1,您将节省14。但是,如果在运行到7之前又增加一倍,则节省的空间将减少。

这非常糟糕,因为我不尝试所有可能性就不知道如何计算下一个双后卫,这使我们回到O(2 ^ N)。

除外-修剪后为2 ^ N。我计算到-2的“附加费用”为14,但如果在获得最右边的数字之前没有更多的附加费用,则增加了16。如果最右边的数字是5,我会立即知道到-2的边路旅行无法付清。(成本仍为14,最大收益为12)。我也不必考虑到-2然后在达到6之前进行一次侧向行程,因为这总是不如首先直接到达该点。


0

我认为您可以使用广度优先搜索来解决它,只要路径复杂,只要保持不超过2 * N ^ 2个元组(布尔值,整数,整数,整数,字符串),其中字符串就长。

元组是(最小或最大布尔值,最小移动位置,最大移动位置,发出的总辐射,路径历史记录)。

我看到算法是这样的:

  1. 将元组池初始化为单个条目(min,0、0、0,“”)
  2. 在池中找到辐射最小的元素。如果最小值和最大值对应于所有桶的最小值和最大值,则路径历史记录是最佳解决方案。否则,将其从池中删除。
  3. 计算该元组的2个后代,每个后代对应于向左或向右步行到下一个未处理的桶。
  4. 将后代插入池中。如果池中已经有一个元素,布尔值,最小值和最大值与新后代相同,则丢弃辐射计数较高的元素。
  5. 转到2。

查找和删除主导的元组将大大提高性能。可能值得在每个元组中添加“已繁殖”标志,并将已繁殖的元组保留在池中。

在决定如何存储元组,以及搜索它们的主导地位和新的育种元素时,还需要做出一些重要的决定。

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.