Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/apache/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Dijkstra变体-无重复组_Python_Algorithm_Graph_Dijkstra_Traveling Salesman - Fatal编程技术网

Python Dijkstra变体-无重复组

Python Dijkstra变体-无重复组,python,algorithm,graph,dijkstra,traveling-salesman,Python,Algorithm,Graph,Dijkstra,Traveling Salesman,我正试图基于Dijkstra的算法编写一个优化过程来寻找最佳路径,但有一点变化,即在寻找最佳路径时不允许从同一组/家庭中选择项目 用蛮力遍历所有边以找到解决方案将是np难的,这就是为什么我试图(希望)使用Dijkstra的算法,但我正在努力添加无重复组逻辑 把它想象成一个旅行推销员的问题,但我想从纽约到洛杉矶旅行,有一条有趣的路线(从不从同一个团队访问两个类似的城市),并尽量减少我的燃料成本。大约有15天和40个城市,但为了定义我的计划,我将其缩减为4个城市和3天 有效路径不必访问每个组,它们只

我正试图基于Dijkstra的算法编写一个优化过程来寻找最佳路径,但有一点变化,即在寻找最佳路径时不允许从同一组/家庭中选择项目

用蛮力遍历所有边以找到解决方案将是np难的,这就是为什么我试图(希望)使用Dijkstra的算法,但我正在努力添加无重复组逻辑

把它想象成一个旅行推销员的问题,但我想从纽约到洛杉矶旅行,有一条有趣的路线(从不从同一个团队访问两个类似的城市),并尽量减少我的燃料成本。大约有15天和40个城市,但为了定义我的计划,我将其缩减为4个城市和3天

有效路径不必访问每个组,它们只是不能访问同一组中的两个城市。{XL,L,S}是有效的解决方案,但是{XL,L,XL}无效,因为它访问了XL组两次。所有有效解决方案的长度相同(15天或边缘),但可以使用组的任意组合(不包括复制组),且无需全部使用(因为15天,但有40个不同的城市组)

下面是一张我放在一起用来说明有效和无效路线的图片:(仅供参考-组是矩阵中的水平行)

最佳路径为G1->G2->G3,但标准Dijkstra解决方案返回G1-

我在网上找到并调整了这个示例代码,并使用以下语法命名我的节点,这样我就可以通过剪切第三个字符快速检查它们属于哪一天和哪一组:D[day#][group#]

## 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')
##基于此处找到的代码:https://raw.githubusercontent.com/nvictus/priority-queue-dictionary/0eea25fa0b0981558aa780ec5b74649af83f441a/examples/dijkstra.py
导入pqdict
def dijkstra(图形、源、目标=无):
"""
计算从源顶点到中每个其他顶点的最短路径
图表
"""
#整个主循环是O((m+n)logn),其中n是
#顶点,m是边的数目。如果图是连通的
#(也就是说,图形是一个整体),m通常支配n,使
#算法O(m logn)整体。
dist={}
pred={}
predGroups={}
#在优先级队列字典中存储距离分数
pq=pqdict.pqdict()
对于图形中的节点:
如果节点==源:
pq[节点]=0
其他:
pq[节点]=浮点('inf')
#从pqdict:O(日志n)中移除“边界”边缘的头部节点。
对于节点,pq.iteritems()中的最小距离:
#图中的每个节点只处理一次。
#总的来说,这是O(n log n)。
距离[节点]=最小距离
如果节点==目标:
打破
#使用pqdict更新任何边节点的分数为O(logn)。
#图形中的每个边最多有一个分数更新。
#总的来说,这是O(m log n)。
对于图[node]中的邻居:
如果pq中有邻居:
新的_分数=距离[节点]+图形[节点][邻居]
#这是我尝试跟踪是否已使用此组/族中的节点
#组标识符存储为节点名称中的第四个字符,以便快速访问
尝试:
groupToAdd=节点[2]
alreadyVisited=predGroups.get(groupToAdd,False)
除:
alreadyVisited=错误
groupToAdd='S'
#用这条线可以吗
如果新的_分数
您是想访问每个小组,还是只是想从A点到达B点?如果是前者,这是NP难的(因为你可以采取退化的情况,每组只有一个城市,并恢复TSP)。两者都是-从起点到终点的距离最短,并且对我沿途访问的城市有限制(或符合有效路线的路线)。例如,我不想访问所有“大”城市城市,我只想参观1个特大型,1个大型,1个中型都是组。组是每个城市的一个属性,我希望我访问2个XL城市的任何路线在确定最短路线时无效。这有意义吗?如果我可以访问一个XL,一个M,但没有L到达那里怎么办?这是一个有效的解决方案吗?如果没有,这是NP完全的,你应该研究一个动态规划解决方案改为“开”。@Kevin-您建议的路径将是有效的-路径不必访问每个组。我在c上发布了一个链接,指向我在原始图片帖子中扔进的图表
## 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')