日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

ortools解决tsp_ortools系列:路由问题1

發布時間:2024/9/19 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ortools解决tsp_ortools系列:路由问题1 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

ortools系列:路由問題1

1. 路由問題

運籌學中最有趣的領域之一是路由,其目標是找到通過復雜網絡傳輸物品的有效路徑。網絡通常用如下圖所示的圖來表示。

每個節點表示一個位置,路由是通過一組節點的路徑。大多數實際的路由問題都涉及到為車輛(汽車、火車、飛機等等)尋找有效的路徑,因此它們通常被稱為車輛路由問題。

路由問題可以分為兩種主要類型:節點路由問題和弧線路由問題,這取決于目標是以訪問節點(位置)還是弧線(連接它們的邊)的形式表示的。我們將給出每個例子。

首先,這里有一個弧線路由問題,如果你看過谷歌地圖街景,你可能想知道谷歌是如何在全世界數百萬個地址獲得街道級別的圖像的。答案很簡單:谷歌的一個團隊駕駛著一隊裝備有自動拍攝每個地址照片的攝像頭的車隊,持續行駛在世界各地的道路上。谷歌的問題是為每輛在指定區域內穿越每條街道的車輛構造最短的路線。如果你用一個圖來表示這個問題,其中弧線代表街道,而節點是街道的交叉點,那么弧線路由問題就是找出穿過圖中每個弧線的最短路徑。谷歌每天使用ortools中提供的技術來解決這個問題。

節點路由問題的一個例子是車輛路由。假設一個公司需要使用車隊將包裹運送到不同的地點。在這個問題的圖中,節點表示位置,弧線表示它們之間的路由。每條弧線都有一個重量,對應于該路線的運行成本。問題:在圖中找到一組路徑(對應于每輛車的送貨路線),其中包含每個目的地,同時最小化總成本。這與弧路由問題不同,因為路徑不必遍歷每個弧,只需包含每個節點。

OR-Tools包括一個專門的路由庫來解決許多類型的節點路由問題:Traveling Salesman Problems (TSP),旅行商問題,這個問題非常著名,也是編程中一個基本問題,在編程領域通常用動態規劃解決,現在很多用智能算法比如遺傳算法等求解。當然如果你把它看成是一個運籌學的路由問題,就用運籌學的思路解決。

Vehicle Routing Problems (VRP), 這個問題類似收快遞或送快遞,比如說,有100個快遞需要送到100個客戶手中,但是一輛車只能送30個快遞,需要怎么安排成本最小或最快的問題。

Capacitated Vehicle Routing Problems (CVRP),有約束的VRP問題,比如每輛車都有載重限制等。

Vehicle Routing Problems with Time Windows (VRPTW), 時間限制,車輛必須在一定時間內開始或完成任務。

Vehicle Routing Problems with Resource Constraints, 倉庫可能有車輛限制,或車輛需要補充燃料。

Vehicle Routing Problems with Pickup and Delivery (VRPPD),車輛在交付客戶前必須先取貨。

我們看到,這些都是同一類問題,但是有不同的約束條件,比如車輛載重限制,時間限制,或者倉庫限制等,針對不同的場景分別建模,效果會好得多,ortools也是這樣做的。

注意:需要說明的是,還有其他的解決方案,如Concorde,致力于解決非常大的tsp優化,這已經超過了ortools的能力范圍。然而,ortools提供了一個更好的平臺來解決包含純TSP之外的約束的更一般的路由問題。

2. TSP問題1

旅行商問題是計算機科學中最著名的問題之一。在下面的內容中,我們講解如何解決TSP問題。

在推銷員挨家挨戶兜售真空吸塵器和百科全書的年代,他們不得不計劃自己的路線,從一家到另一家,從一個城市到另一個城市。路線越短越好。查找訪問一組地點的最短路徑是一個指數難度的問題:查找20個城市的最短路徑的難度是查找10個城市的兩倍多。

對所有可能的路徑進行徹底的搜索將確保找到最短的路徑,但是對于除小的位置集之外的所有路徑,這在計算上都是棘手的。對于較大的問題,需要使用優化技術來智能搜索解空間,找到近似最優解。

在數學上,旅行商問題可以表示為一個圖,其中的位置是節點,而邊(或弧)表示節點之間的直接路由。每條邊的權值是節點之間的距離。目標是找到權值之和最短的路徑。下面,我們看到一個簡單的四節點圖,以及訪問每個節點的最短周期:

OR-Tools除了為經典的旅行商問題尋找解決方案外,還提供了針對更一般類型的tsp的方法,包括:傳統的TSP是對稱的:不對稱成本問題從A點到B點的距離等于從A點B點的距離不過,航運物品的成本從A點到B點的成本可能不等于把A點B點或工具也可以處理成本不對稱的問題。

Prize-collecting TSP:從訪問節點中獲益。

帶有時間窗口的TSP。

我們來看這么一個例子,在美國的13個城市,不同城市之間的距離已經知道,現在需要找到一條路徑,每個城市只訪問一次,需要訪問所有城市,該怎么走,才能使這條路徑最短呢?

OK,讓我們來擼代碼:

from ortools.constraint_solver import pywrapcp

from ortools.constraint_solver import routing_enums_pb2

# 距離的回調函數,用于計算兩個節點之間的距離

# 在后面的例子中我們也會看到類似的回調函數,只是計算節點間距離方法不一樣而已

def create_distance_callback(dist_matrix):

# Create a callback to calculate distances between cities.

def distance_callback(from_node, to_node):

return int(dist_matrix[from_node][to_node])

return distance_callback

def main():

# 一共13個城市,以及城市之間的距離

city_names = ["New York", "Los Angeles", "Chicago", "Minneapolis",

"Denver", "Dallas", "Seattle", "Boston", "San Francisco",

"St. Louis", "Houston", "Phoenix", "Salt Lake City"]

# Distance matrix

dist_matrix = [

[0, 2451, 713, 1018, 1631, 1374, 2408, 213, 2571, 875, 1420, 2145, 1972], # New York

[2451, 0, 1745, 1524, 831, 1240, 959, 2596, 403, 1589, 1374, 357, 579], # Los Angeles

[713, 1745, 0, 355, 920, 803, 1737, 851, 1858, 262, 940, 1453, 1260], # Chicago

[1018, 1524, 355, 0, 700, 862, 1395, 1123, 1584, 466, 1056, 1280, 987], # Minneapolis

[1631, 831, 920, 700, 0, 663, 1021, 1769, 949, 796, 879, 586, 371], # Denver

[1374, 1240, 803, 862, 663, 0, 1681, 1551, 1765, 547, 225, 887, 999], # Dallas

[2408, 959, 1737, 1395, 1021, 1681, 0, 2493, 678, 1724, 1891, 1114, 701], # Seattle

[213, 2596, 851, 1123, 1769, 1551, 2493, 0, 2699, 1038, 1605, 2300, 2099], # Boston

[2571, 403, 1858, 1584, 949, 1765, 678, 2699, 0, 1744, 1645, 653, 600], # San Francisco

[875, 1589, 262, 466, 796, 547, 1724, 1038, 1744, 0, 679, 1272, 1162], # St. Louis

[1420, 1374, 940, 1056, 879, 225, 1891, 1605, 1645, 679, 0, 1017, 1200], # Houston

[2145, 357, 1453, 1280, 586, 887, 1114, 2300, 653, 1272, 1017, 0, 504], # Phoenix

[1972, 579, 1260, 987, 371, 999, 701, 2099, 600, 1162, 1200, 504, 0]] # Salt Lake City

# 定義TSP問題的參數

tsp_size = len(city_names) # 網絡中節點的數量

num_routes = 1 # 定義路由數,TSP為1

depot = 0 # 路由的開始和結束節點,0表示從New York出發,最后要回到New York

# 創建路由模型,需要指定路由的參數

routing = pywrapcp.RoutingModel(tsp_size, num_routes, depot)

search_parameters = pywrapcp.RoutingModel.DefaultSearchParameters()

# 創建距離回調函數,用于計算兩個節點之間的距離

dist_callback = create_distance_callback(dist_matrix)

routing.SetArcCostEvaluatorOfAllVehicles(dist_callback)

# Solve the problem.

# 求解并打印結果

assignment = routing.SolveWithParameters(search_parameters)

if assignment:

# 最小距離

print("Total distance: " + str(assignment.ObjectiveValue()) + " miles\n")

# 規劃路徑結果

# Only one route here; otherwise iterate from 0 to routing.vehicles() - 1

route_number = 0

index = routing.Start(route_number) # Index of the variable for the starting node.

route = ''

while not routing.IsEnd(index):

# Convert variable indices to node indices in the displayed route.

# IndexToNode 求當前節點的對應的編號

# NextVar 當前節點的下一個節點,當然還要再外層套上assignment.Value

route += str(city_names[routing.IndexToNode(index)]) + ' -> '

index = assignment.Value(routing.NextVar(index))

route += str(city_names[routing.IndexToNode(index)])

print("Route:\n\n" + route)

else:

print('No solution found.')

if __name__ == '__main__':

main()

# 結果

Total distance: 7293 miles

Route:

New York -> Boston -> Chicago -> Minneapolis -> Denver

-> Salt Lake City -> Seattle -> San Francisco

-> Los Angeles -> Phoenix -> Houston -> Dallas

-> St. Louis -> New York

注意,因為路由解決程序使用整數進行所有計算,所以距離回調需要將距離回調返回的值轉換為整數。在上面的例子中,轉換由Python int()函數完成。雖然在這種情況下不需要進行轉換,因為所有的距離都是整數,但是建議始終將回調的返回值轉換為整數。

3. TSP問題2-鉆線路

這個例子是用自動鉆孔機在電路板上鉆孔,問題是為了鉆完所有需要的孔,找到鉆板的最短路徑。該示例取自TSP問題庫TSPLIB。

見下圖,和TSP是一個問題,只是看起來更復雜而已,不過距離函數計算不同,在前面的問題中,距離直接給出來了,而這里需要自己計算歐拉距離。

下面是python代碼,就不注釋了。

import math

from ortools.constraint_solver import pywrapcp

from ortools.constraint_solver import routing_enums_pb2

def euclid_distance(x1, y1, x2, y2):

# 歐式距離計算

dist = math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)

return dist

def create_distance_matrix(locations):

# Create the distance matrix.

size = len(locations)

dist_matrix = {}

for from_node in range(size):

dist_matrix[from_node] = {}

for to_node in range(size):

x1 = locations[from_node][0]

y1 = locations[from_node][1]

x2 = locations[to_node][0]

y2 = locations[to_node][1]

dist_matrix[from_node][to_node] = euclid_distance(x1, y1, x2, y2)

return dist_matrix

def create_distance_callback(dist_matrix):

# Create the distance callback.

def distance_callback(from_node, to_node):

return int(dist_matrix[from_node][to_node])

return distance_callback

def main():

# Create the data.

locations = create_data_array()

dist_matrix = create_distance_matrix(locations)

dist_callback = create_distance_callback(dist_matrix)

tsp_size = len(locations)

num_routes = 1

depot = 0

# Create routing model.

if tsp_size > 0:

routing = pywrapcp.RoutingModel(tsp_size, num_routes, depot)

search_parameters = pywrapcp.RoutingModel.DefaultSearchParameters()

routing.SetArcCostEvaluatorOfAllVehicles(dist_callback)

# Solve the problem.

assignment = routing.SolveWithParameters(search_parameters)

if assignment:

# Solution cost.

print("Total distance: " + str(assignment.ObjectiveValue()) + "\n")

# Inspect solution.

# Only one route here; otherwise iterate from 0 to routing.vehicles() - 1.

route_number = 0

node = routing.Start(route_number)

start_node = node

route = ''

while not routing.IsEnd(node):

route += str(node) + ' -> '

node = assignment.Value(routing.NextVar(node))

route += '0'

print("Route:\n\n" + route)

else:

print('No solution found.')

else:

print('Specify an instance greater than 0.')

def create_data_array():

locations = [[288, 149], [288, 129], [270, 133], [256, 141], [256, 157], [246, 157], [236, 169],

[228, 169], [228, 161], [220, 169], [212, 169], [204, 169], [196, 169], [188, 169], [196, 161],

[188, 145], [172, 145], [164, 145], [156, 145], [148, 145], [140, 145], [148, 169], [164, 169],

[172, 169], [156, 169], [140, 169], [132, 169], [124, 169], [116, 161], [104, 153], [104, 161],

[104, 169], [90, 165], [80, 157], [64, 157], [64, 165], [56, 169], [56, 161], [56, 153], [56, 145],

[56, 137], [56, 129], [56, 121], [40, 121], [40, 129], [40, 137], [40, 145], [40, 153], [40, 161],

[40, 169], [32, 169], [32, 161], [32, 153], [32, 145], [32, 137], [32, 129], [32, 121], [32, 113],

[40, 113], [56, 113], [56, 105], [48, 99], [40, 99], [32, 97], [32, 89], [24, 89], [16, 97],

[16, 109], [8, 109], [8, 97], [8, 89], [8, 81], [8, 73], [8, 65], [8, 57], [16, 57], [8, 49],

[8, 41], [24, 45], [32, 41], [32, 49], [32, 57], [32, 65], [32, 73], [32, 81], [40, 83], [40, 73],

[40, 63], [40, 51], [44, 43], [44, 35], [44, 27], [32, 25], [24, 25], [16, 25], [16, 17], [24, 17],

[32, 17], [44, 11], [56, 9], [56, 17], [56, 25], [56, 33], [56, 41], [64, 41], [72, 41], [72, 49],

[56, 49], [48, 51], [56, 57], [56, 65], [48, 63], [48, 73], [56, 73], [56, 81], [48, 83], [56, 89],

[56, 97], [104, 97], [104, 105], [104, 113], [104, 121], [104, 129], [104, 137], [104, 145],

[116, 145], [124, 145], [132, 145], [132, 137], [140, 137], [148, 137], [156, 137], [164, 137],

[172, 125], [172, 117], [172, 109], [172, 101], [172, 93], [172, 85], [180, 85], [180, 77],

[180, 69], [180, 61], [180, 53], [172, 53], [172, 61], [172, 69], [172, 77], [164, 81], [148, 85],

[124, 85], [124, 93], [124, 109], [124, 125], [124, 117], [124, 101], [104, 89], [104, 81],

[104, 73], [104, 65], [104, 49], [104, 41], [104, 33], [104, 25], [104, 17], [92, 9], [80, 9],

[72, 9], [64, 21], [72, 25], [80, 25], [80, 25], [80, 41], [88, 49], [104, 57], [124, 69],

[124, 77], [132, 81], [140, 65], [132, 61], [124, 61], [124, 53], [124, 45], [124, 37], [124, 29],

[132, 21], [124, 21], [120, 9], [128, 9], [136, 9], [148, 9], [162, 9], [156, 25], [172, 21],

[180, 21], [180, 29], [172, 29], [172, 37], [172, 45], [180, 45], [180, 37], [188, 41], [196, 49],

[204, 57], [212, 65], [220, 73], [228, 69], [228, 77], [236, 77], [236, 69], [236, 61], [228, 61],

[228, 53], [236, 53], [236, 45], [228, 45], [228, 37], [236, 37], [236, 29], [228, 29], [228, 21],

[236, 21], [252, 21], [260, 29], [260, 37], [260, 45], [260, 53], [260, 61], [260, 69], [260, 77],

[276, 77], [276, 69], [276, 61], [276, 53], [284, 53], [284, 61], [284, 69], [284, 77], [284, 85],

[284, 93], [284, 101], [288, 109], [280, 109], [276, 101], [276, 93], [276, 85], [268, 97],

[260, 109], [252, 101], [260, 93], [260, 85], [236, 85], [228, 85], [228, 93], [236, 93],

[236, 101], [228, 101], [228, 109], [228, 117], [228, 125], [220, 125], [212, 117], [204, 109],

[196, 101], [188, 93], [180, 93], [180, 101], [180, 109], [180, 117], [180, 125], [196, 145],

[204, 145], [212, 145], [220, 145], [228, 145], [236, 145], [246, 141], [252, 125], [260, 129],

[280, 133]]

return locations

if __name__ == '__main__':

main()

# 結果

Total distance: 2790

Route:

0 -> 1 -> 279 -> 2 -> 278 -> 277 -> 248 -> 247 -> 243 -> 242 -> 241

-> 240 -> 239 -> 238 -> 245 -> 244 -> 246 -> 249 -> 250 -> 229 -> 228

……

-> 276 -> 3 -> 4 -> 0

那么長的代碼不用細看,看幾個關鍵點就好了。上面兩個例子只是練手,其實沒多大用處,接下來將的VRP問題就用處就比較直接了,當然,現實業務可不這么簡單,總是有各種各樣的狀況要考慮,不管是簡化模型也好,增加各種約束也好,開開心心干活是不存在的。

敬請期待。

4. 參考

大家看完記得關注點贊.

master蘇.

總結

以上是生活随笔為你收集整理的ortools解决tsp_ortools系列:路由问题1的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。