我的目标是找到与道路(边缘)连接的给定城市(顶点)之间的最短路径(最低成本)。 每条道路和每个城市都有费用(成本),在进入该道路/城市之前必须支付。
如果这就是整个任务,我将使用 Dijkstra 算法来找到最短路径(并将城市成本添加到之前连接的道路的成本中)。
但是:
城市有类似合作伙伴协议之类的东西 - 当您访问其中一个城市并支付费用时,进入该特定合作伙伴关系的其他城市是免费。
因此,顶点(在其之前连接的边)的成本取决于已经遍历的顶点。
有没有解决这类问题的算法?
谢谢你。
您可以将设置覆盖问题减少到这一点。这意味着你的问题是 NP 难的,你不应该期望找到一个有效的解决方案(一般来说)。
这意味着您应该希望伙伴关系的数量很少,也许这样您就可以考虑非单一道路/城市伙伴关系的所有可能子集,并为每个子集找到最短路径(假设您的路径将经过仅您正在考虑的给定子集中的道路/城市)。那么你的算法将在 2^P * (N+M) 时间内运行,其中 P 是伙伴关系的数量,N 和 M 分别是城市和道路的数量。
为了完整起见,以下是从集合覆盖到图形问题的简化:
集合覆盖问题是给定一个有限集合 S = {s[1], ..., s[n]} 和 S 的子集:S[1], S[1], S[2 ],...,S[N]。您需要找到覆盖 S 的这些子集的最小数量。
要使用您的城市问题来找到最小覆盖范围,请构建一个像这样的图表。设图的顶点为 START、END 和 (S[i], t) 对,其中 t 位于 S[i] 中。在图形中添加边:
设边权重均为1,进入成本(S[i], s)也为1。所有城市/顶点(S[i], s), (S[i], t)共享相同的成本。没有两条道路/边缘共享成本。
现在,从 START 到 END 的最低成本路径对应于找到覆盖 S 的 S[i] 的最小集合。该路径的成本将为 1 + n + p,其中 p 是最小覆盖的大小。
这里要做的是聚类。
在开始运行 Dijkstra 或某种其他算法之前,请对图表进行一些更改,其中所有彼此达成协议的城市都将转换为一个新节点。
从这个节点,您可以到达从其中任何一个城市到达的任何城市(当然选择最便宜的边缘)。
这与将两个达成协议城市之间的边缘的相关道路的收费更改为
0
非常相似。
Dijkstra 非常适合这个问题,如果你建模得当的话。
正确地说,我的意思是您需要认识到卡车的状态不仅是其当前位置,而且是其历史记录。
class TruckState {
City current;
List<City> visited;
}
注意:如果入场费保守,顺序可能并不重要(协议条款中的所有城市都提供相同的成本效益,无论顺序如何?)。如果是这样,将历史表示为
Set
,您将获得更小的搜索空间:
class TruckState {
City current;
Set<City> visited;
}
这一切使得你的搜索空间相当大。如果您的合作伙伴模式允许,您可能会再次进一步减少。例如,卡车的有用状态可能是其位置,以及未锁定的
Set
。如果这些可解锁的协议少于城市,则您可以将您的州压缩到最低限度。Agreements
class TruckState {
City current;
Set<Agreement> unlocked;
}
非常困难,因为找到一个可接受的启发式将不是微不足道的。我无法提供建议,因为我不知道您的成本是否包括某种类型的距离函数。就目前情况而言,由于成本可能会根据状态而变为零,因此唯一可接受的启发式可能是恒定值class TruckState {
City current;
Map<Agreement, City> visited;
}
。没用...