严重困在图形任务上

时间:2015-04-10 18:42:48

标签: algorithm graph graph-algorithm

  

您有一个包含K个港口和N个城市的图表,每个城市都有M个船只   每个都带有X个负载单元的端口(所有这些都是满载的   一开始,无法在任何时间重新加载,所有这些都带有   相同数量的货物)。每个城市都需要一定数量的货物(可能   需要相同的数量,可能不会 - 取决于输入)和一艘船可以   如果满足城市的全部需求,只能在城市卸货   (即如果一个城市需要10个单位的货物,你就不能从一个城市卸下7个   船和3从另一个 - 任何一个供应所有10个单位或它有   没有停在那里的生意。)

     

每个端口都连接到其他所有端口和其他所有城市   (城市也相互联系 - 基本上一切都是   连接所有东西)你知道每个点的距离   对任何其他人。所有的最小成本(距离之和)是多少   船舶必须穿越,如果全部的话,它们各自的路线是什么   城市必须满足他们的需求,每艘船都必须结束它   从它开始的同一个港口旅行?

这是我正在努力解决问题解决技巧的一项任务。我想到了选择最近的城市然后去最接近的城市的贪婪方法,但这不符合一个简单的情况(假设每个港口有一艘船):

C1 <--11km--> P1 <--10km--> C2 <--10km--> P2 
where P are ports and C are cities 
(There should also be direct edges from C1 to C2 or P1 to P2 for example 
but I omitted them for clarity - let's just assume here all the verices
lie on the same line and so we could ignore them)

因为来自P1的船将进入C2,因此使得到达C1的路线更长,而最佳解决方案是它将进入更远的C1并且让船从P2处理C2。那么解决这个问题的正确方法是什么?或者它可能是NP-complete而且没有?例如,我尝试用TSP来考虑它,但它不太相似,因为你不在这里寻找汉密尔顿循环。

2 个答案:

答案 0 :(得分:1)

你的问题是NP难的,如下所示。想象一下,你有两个港口,你在一个港口有2艘船,在另一个港口有你想要的船只,从第一个港口到任何城市的旅行费用基本上为零,从第二个港口到任何城市都非常大。还想象从任何城市到另一个城市旅行的成本非常小。假设每艘船的货物容量均为M,城市的总货物需求量为2 * M.然后你想把城市分成两组,每组城市的总需求是M,这样你就可以使用容量为M的两艘从第一个港口便宜的旅行费用。否则你必须使用其他港口的其他船只,并产生非常大的旅行费用。然而,将一组数字拆分成具有相同总和的两个不相交集合是NP完全问题。因此,你的问题是NP难的。

因此,启发式或蛮力可能是你最好的选择。

答案 1 :(得分:0)

好的,所以我认为你可以用A *状态空间搜索算法做到这一点。它类似于Dykstra的最短路径,但在节点上使用启发式功能。

我认为您可以将一个船舶旅程建模为图表上的边缘,每个节点将包含您的信息,包括每艘船的位置,货物的数量以及每个城市的货物运输量。

State node:
  List of ships
  List of cities

Ship:
  Cargo Capacity
  Current Location

City:
  Cargo Delivered

所以上面只是为每个州存储的数据。其他数据,如船舶的本土城市,或城市所需的总货物数量,不能通过行动来改变,因此它不属于国家,它只是有用的背景信息。

图表上的边缘将是移动船舶并在其成为城市时运送货物的动作。边缘权重就是城市之间的距离。

您还必须制作启发式函数,为每个州提供一种适应度值。我们希望低适应值是好的,而高则是坏的。启发式算法的一个想法是查看加在一起的所有城市仍然需要的货物数量,加上每艘船不是在其本国港口加上1。这种启发式不一致或不可接受,我不相信。这是一种健身功能。

另一个启发式选项是计算未完全供应的城市,并添加不在其港口的船舶数量。这种启发式方法是可以接受的(从不估计高于实际成本),但我不确定它是否会更好。您可以通过很多方式进行启发式搜索。

然后你需要的另一个主要功能是Expand(Node n)函数,它根据你可以采取的所有可能行动为你提供所有可能的后继状态。

无论你使用哪种启发式,如果你处于目标状态,你应该让它返回零。因此,如果所有城市都有货物,并且所有船只都在其港口,那么它将返回零。

然后你只需通过标准的A *搜索来运行它!如果您不熟悉维基百科页面,请点击此页面。我确信还有很多其他好的资源可供学习。如果您想对A *算法部分问题进行更多解释,请与我们联系。 http://en.wikipedia.org/wiki/A*_search_algorithm

一旦你覆盖了我提到的东西,你就拥有了所有的构建块:状态的表示,启发式函数可以访问的背景信息,还检查目标状态的启发式函数,以及基于后继状态的扩展函数在可能的动作上,使用背景数据计算边缘权重。现在你只是在实现A *搜索算法时使用这几个构建块,而bam,你有一个很好的解决方案。请记住,它可能不是最佳解决方案,可能无法保证找到解决方案。我相信启发式函数的属性(可接受和/或一致吗?)将决定是否保证解决方案或最佳解决方案。