Dijkstra的变种 - 没有重复的群体

时间:2015-09-09 14:00:58

标签: python algorithm graph dijkstra traveling-salesman

我尝试编写基于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 - 组是矩阵中的水平行)enter image description here

**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')

0 个答案:

没有答案