主要内容

旅行推销员问题:Solver-Based

这个例子展示了如何使用二进制整数规划来解决经典的旅行商问题。这个问题涉及找到最短的封闭之旅(路径)通过一组停止(城市)。在这种情况下,有200停止,但你可以很容易地改变nStops变量大小不同的问题。你会解决最初的问题,看到解决方案subtours。这意味着最优解发现没有给一个连续路径通过所有的点,而是有几个断开连接的循环。然后您将使用一个迭代过程确定subtours,添加约束和运行优化直到subtours消除。

具体问题具体分析的方法,请参阅旅行推销员问题:具体问题具体分析

问题公式化

制定的旅行推销员问题整数线性规划如下:

  • 生成所有可能的旅行,这意味着所有的成对的停止。

  • 计算每个旅行的距离。

  • 成本函数最小化旅行距离之和为每个访问之旅。

  • 决策变量是二进制,与每一个旅行,其中每个1表示存在于旅游的行程,和每个0代表一个旅行而不是旅游。

  • 确保旅游包括每一停止,包括线性约束,每一站到底两次。这意味着一个到来,一个离开停止。

生成停止

生成随机停止在一个原油的多边形表示美国大陆

负载(“usborder.mat”,“x”,“y”,“xx”,“yy”);rng (3“旋风”)%情节与停在缅因州、佛罗里达州,并且是可再生的nStops = 200;%你可以用任意数量,但问题规模的N ^ 2stopsLon = 0 (nStops, 1);%分配nStops x坐标stopsLat = stopsLon;%分配坐标n = 1;(n < = nStops) xp =兰特* 1.5;yp =兰德;如果inpolygon (xp, yp, x, y)%在边界测试stopsLon (n) = xp;stopsLat (n) = yp;n = n + 1;结束结束

计算点之间的距离

因为有200停止,19900年有19900次,这意味着二进制变量(变量= 200号选择2)。

生成所有的旅行,这意味着所有成对的停止。

idx = nchoosek (1: nStops, 2);

计算所有旅行的距离,假设地球是平为了使用毕达哥拉斯规则。

dist =函数(stopsLat (idx (: 1))——stopsLat (idx (:, 2)),stopsLon (idx (: 1))——stopsLon (idx (:, 2)));lendist =长度(经销);

这个定义的经销向量,参观的长度

dist”* x_tsp

在哪里x_tsp是二进制解向量。这是旅行的距离,你尽量减少。

创建图表,画地图

代表图的问题。创建一个图形,停止节点和边旅行。

图G = (idx (: 1), idx (:, 2));

用图表显示停止阴谋。阴谋没有图形边缘节点。

图hGraph =情节(G,“XData”stopsLon,“YData”stopsLat,“线型”,“没有”,“NodeLabel”,{});持有%画出边界之外情节(x, y,的r -)举行

约束

创建线性约束,每一站有两个相关的旅行,因为必须有一个去每一站和离开每一站的旅程。

Aeq = spalloc (nStops、长度(idx) nStops * (nStops-1));%分配一个稀疏矩阵2 = 1:nStops whichIdxs = (idx = = 2);%的旅行,包括停止二世whichIdxs =稀疏(sum (whichIdxs, 2));%包括旅行二世的两端Aeq (ii):) = whichIdxs ';%包含在约束矩阵结束说真的= 2 * 1 (nStops 1);

二进制界限

所有的决策变量都是二进制的。现在,设置intcon参数决策变量的数量,给每一个下界(0),和1的一个上界。

intcon = 1: lendist;1磅= 0 (lendist);乌兰巴托= 1 (lendist, 1);

优化使用intlinprog

问题是准备解决方案。抑制迭代输出,关闭默认显示。

选择= optimoptions (“intlinprog”,“显示”,“关闭”);[x_tsp, costopt exitflag、输出]= intlinprog(经销、intcon [], [], Aeq,说真的,磅,乌兰巴托,选择);

创建一个新的旅行作为边缘图的解决方案。为此,在解决方案中一些值不是整数,并转换生成的值逻辑

x_tsp =逻辑(圆(x_tsp));Gsol =图(idx (x_tsp, 1), idx (x_tsp, 2), [], numnodes (G));% Gsol =图(idx (x_tsp, 1), idx (x_tsp 2));%在大多数情况下同样适用

可视化解决方案

持有突出(hGraph Gsol,“线型”,“- - -”)标题(“解决方案与Subtours”)

在地图上可以看到,解决方案有几个subtours。到目前为止没有指定的约束阻止这些subtours发生。为了防止任何可能的subtour情况发生,你将需要一个令人难以置信的大量的不等式约束。

Subtour约束

因为你不能添加的所有subtour约束,采用迭代的方法。检测subtours在当前的解决方案,然后添加不等式约束,以防止这些特定的subtours发生。通过这样做,你会找到一个合适的旅游在一些迭代。

消除subtours不等式约束。这是如何工作的一个例子是如果你有5分subtour,然后是五行连接这些点来创建subtour。消除这种subtour通过实现一个不等式约束说必须小于或等于四行这5分之间。

更多,找到所有这些5分之间的界限,限制的解决方案没有超过四行。这是一个正确的约束,因为如果5或更多的行中存在一个解决方案,解决方案会有subtour(图表 n 节点和 n 边缘总是包含一个周期)。

检测subtours通过确定连接组件Gsol与边缘图,建立在当前的解决方案。conncomp返回一个向量的数量每条边所属subtour。

tourIdxs = conncomp (Gsol);numtours = max (tourIdxs);%的subtours数量流(“# subtours: % d \ n”,numtours);
# subtours: 27

包括线性不等式约束来消除subtours,反复调用解算器,直到只剩下一个subtour。

lendist = spalloc (0, 0);%分配一个稀疏矩阵线性不等式约束b = [];numtours > 1直到只有一个subtour %重复%添加subtour约束b = [b; 0 (numtours, 1)];%分配bA = [; spalloc (numtours、lendist nStops)];%猜测有多少零来分配2 = 1:numtours rowIdx =大小(A, 1) + 1;%为索引计数器subTourIdx =找到(tourIdxs = = 2);当前subtour %提取%的下一行找到所有相关的变量%特定subtour,然后添加一个不等式约束禁止%,subtour和所有使用这些subtours停止。变化= nchoosek(1:长度(subTourIdx), 2);jj = 1:长度(变化)whichVar =(总和(idx = = subTourIdx(变化(jj, 1), 2)) &(和(idx = = subTourIdx(变化(jj, 2)), 2));(rowIdx whichVar) = 1;结束b (rowIdx) =长度(subTourIdx) - 1;%不如subtour停止旅行结束%再次优化[x_tsp, costopt exitflag、输出]= intlinprog(经销、intcon A、b Aeq,说真的,磅,乌兰巴托,选择);x_tsp =逻辑(圆(x_tsp));Gsol =图(idx (x_tsp, 1), idx (x_tsp, 2), [], numnodes (G));% Gsol =图(idx (x_tsp, 1), idx (x_tsp 2));%在大多数情况下同样适用%可视化的结果hGraph。线型=“没有”;%删除之前的突出显示的路径突出(hGraph Gsol,“线型”,“- - -”)drawnow%多少subtours呢?tourIdxs = conncomp (Gsol);numtours = max (tourIdxs);%的subtours数量流(“# subtours: % d \ n”numtours)结束
# subtours: 20 # subtours: 7 # subtours: 9 # subtours: 9 # subtours: 3 # subtours: 2 # subtours: 7 # subtours: 2 # subtours: 1
标题(“解决方案与Subtours消除”);持有

解决方案质量

解决方案是一个可行的旅游,因为它是一个闭环。但这是最小成本之旅吗?发现的一个方法是检查输出结构。

disp (output.absolutegap)
0

渺小的绝对差距意味着解决方案是最优或接近最优的总长度。

相关的话题