簡體   English   中英

旅行商問題的虛擬節點

[英]Dummy node for Traveling Salesman Problem

最近我一直在閱讀很多關於 TSP 的內容,我需要創建一個 TSP 的變體,其中

  1. 我不在乎起點(可以是任何城市)和
  2. 結束城市不必與起始城市相同

顯然,這可以使用一個虛擬節點來實現 - 到每個其他節點的距離為 0: source這是否意味着輸入: cityAcityBcityCcityDcityE矩陣表示應該如下所示:

[
[0,9,6,1,3]
[9,0,4,2,1]
[6,4,0,9,1]
[1,2,9,0,8]
[3,1,1,8,0]
[0,0,0,0,0]
]

這是正確的方法,如果不是,那為什么? 我仍然對理解為什么額外的虛擬節點工作以通過我的變體獲得路徑感到困惑。 謝謝

根據上面的評論,這是一個沒有虛擬節點的示例:

import functools
import math

def shortest_path(arr):
    
    n = len(arr)
    bitmask = [1 << i for i in range(n)]
    target = (1 << n) - 1
    
    @functools.lru_cache(None)
    def helper(city, visited):
        nonlocal target, n
        
        if visited == target:
            return 0, [city]
        
        best = math.inf, []
        for neigh in range(n):
            if not (visited & bitmask[neigh]):
                cost, path = helper(neigh, visited | bitmask[neigh])
                cost += arr[city][neigh]
                path = [city] + path
                if cost < best[0]:
                    best = cost, path
        return best
    
    best, best_path = math.inf, []
    for start in range(n):
        total_distance, path = helper(start, bitmask[start])
        if total_distance < best:
            best, best_path = total_distance, path
    
    return best, best_path

def shortest_path_padded(arr):
    n = len(arr)
    bitmask = [1 << i for i in range(n)]
    target = (1 << n) - 1
    
    @functools.lru_cache(None)
    def helper(city, visited):
        nonlocal target, n
        
        if visited == target:
            return 0, [city]
        
        best = math.inf, []
        for neigh in range(n):
            if not (visited & bitmask[neigh]):
                cost, path = helper(neigh, visited | bitmask[neigh])
                cost += arr[city][neigh]
                path = [city] + path
                if cost < best[0]:
                    best = cost, path
        return best
    
    return helper(0, bitmask[0])


if __name__ == "__main__":
    arr = [
            [0,9,6,1,3],
            [9,0,4,2,1],
            [6,4,0,9,1],
            [1,2,9,0,8],
            [3,1,1,8,0]
          ]
    arr2 = [[0]*(len(arr[0])+1)] + [[0] + row for row in arr]
    
    print(shortest_path(arr))
    print(shortest_path_padded(arr2))
Out: (5, [0, 3, 1, 4, 2])
Out: (5, [0, 1, 4, 2, 5, 3]) # city names + 1 because city 0 is dummy city

使用虛擬節點與嘗試將每個城市作為起始城市有什么不同?

沒什么,如果你從一個與任何其他城市距離為 0 的虛擬節點開始,它的第一選擇就是選擇第一個城市到 go 到。

這個沒有 for 循環和零填充數組的解決方案將與具有 for 循環和數組的解決方案相同。


#NO LIBRARIES
def shortest_path_padded_no_libs(arr):
    n = len(arr)
    bitmask = [1 << i for i in range(n)]
    target = (1 << n) - 1
    
    def helper(city, visited):
        nonlocal target, n
        
        h = (city, visited)
        if h in memo:
            return memo[h]
        
        if visited == target:
            return 0, [city]
        
        best = float('inf'), []
        for neigh in range(n):
            if not (visited & bitmask[neigh]):
                cost, path = helper(neigh, visited | bitmask[neigh])
                cost += arr[city][neigh]
                path = [city] + path
                if cost < best[0]:
                    best = cost, path
                    
        memo[h] = best
        return best
    
    memo = {}
    
    return helper(0, bitmask[0])


if __name__ == "__main__":
    arr = [
            [0,9,6,1,3],
            [9,0,4,2,1],
            [6,4,0,9,1],
            [1,2,9,0,8],
            [3,1,1,8,0]
          ]
    arr2 = [[0]*(len(arr[0])+1)] + [[0] + row for row in arr]
    print(shortest_path_padded_no_libs(arr2))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM