我尝试编写基于Dijkstra算法的优化过程来找到最佳路径,但稍微变化一下,在找到最佳路径时不允许从同一组/系列中选择项目。 / p>
所有边缘的强力遍历以找到解决方案将是np-hard,这就是为什么我试图(希望)使用Dijkstra的算法,但我努力添加无重复小组逻辑。
将其视为旅行推销员的问题,但我想从New Your到Los Angels旅行,并且有一条有趣的路线(从未访问过来自同一组的两个类似城市)并最大限度地降低燃料成本。大约有15天和40个城市,但是为了确定我的计划,我把它减少到4个城市和3天。
有效路径不必访问每个群组,他们只能访问同一群组中的2个城市。 {XL,L,S}是有效的解决方案,但{XL,L,XL}无效,因为它访问XL组两次。所有有效的解决方案都是相同的长度(15天或边缘),但可以使用任何组合组合(没有复制组),不需要全部使用(自15天以来,但有40个不同的城市组)。
这是我放在一起的图片,用以说明有效的&无效路线:( FYI - 组是矩阵中的水平行)
**Day 1**
G1->G2 @ $10
G3->G4 @ $30
etc...
**Day 2**
G1->G3 @ $50
G2->G4 @ $10
etc...
**Day 3**
G1->G4 @ $30
G2->G3 @ $50
etc...
最佳路径将是G1-> G2-> G3,然而标准Dijkstra解决方案返回G1 -
我找到了&在线调整了这个示例代码,并使用以下语法命名我的节点,以便我可以快速查看哪一天&他们属于的组:D [day#] [Group#]切片第3个字符。
## Based on code found here: https://raw.githubusercontent.com/nvictus/priority-queue-dictionary/0eea25fa0b0981558aa780ec5b74649af83f441a/examples/dijkstra.py
import pqdict
def dijkstra(graph, source, target=None):
"""
Computes the shortests paths from a source vertex to every other vertex in
a graph
"""
# The entire main loop is O( (m+n) log n ), where n is the number of
# vertices and m is the number of edges. If the graph is connected
# (i.e. the graph is in one piece), m normally dominates over n, making the
# algorithm O(m log n) overall.
dist = {}
pred = {}
predGroups = {}
# Store distance scores in a priority queue dictionary
pq = pqdict.PQDict()
for node in graph:
if node == source:
pq[node] = 0
else:
pq[node] = float('inf')
# Remove the head node of the "frontier" edge from pqdict: O(log n).
for node, min_dist in pq.iteritems():
# Each node in the graph gets processed just once.
# Overall this is O(n log n).
dist[node] = min_dist
if node == target:
break
# Updating the score of any edge's node is O(log n) using pqdict.
# There is _at most_ one score update for each _edge_ in the graph.
# Overall this is O(m log n).
for neighbor in graph[node]:
if neighbor in pq:
new_score = dist[node] + graph[node][neighbor]
#This is my attempt at tracking if we've already used a node in this group/family
#The group designator is stored as the 4th char in the node name for quick access
try:
groupToAdd = node[2]
alreadyVisited = predGroups.get( groupToAdd, False )
except:
alreadyVisited = False
groupToAdd = 'S'
#Solves OK with this line
if new_score < pq[neighbor]:
#Erros out with this line version
#if new_score < pq[neighbor] and not( alreadyVisited ):
pq[neighbor] = new_score
pred[neighbor] = node
#Store this node in the "visited" list to prevent future duplication
predGroups[groupToAdd] = groupToAdd
print predGroups
#print node[2]
return dist, pred
def shortest_path(graph, source, target):
dist, pred = dijkstra(graph, source, target)
end = target
path = [end]
while end != source:
end = pred[end]
path.append(end)
path.reverse()
return path
if __name__=='__main__':
# A simple edge-labeled graph using a dict of dicts
graph = {'START': {'D11':1,'D12':50,'D13':3,'D14':50},
'D11': {'D21':5},
'D12': {'D22':1},
'D13': {'D23':50},
'D14': {'D24':50},
'D21': {'D31':3},
'D22': {'D32':5},
'D23': {'D33':50},
'D24': {'D34':50},
'D31': {'END':3},
'D32': {'END':5},
'D33': {'END':50},
'D34': {'END':50},
'END': {'END':0}}
dist, path = dijkstra(graph, source='START')
print dist
print path
print shortest_path(graph, 'START', 'END')