朴素约束
最朴素的约束为:每个节点有且仅有两条边。
constr2trips = optimconstr(nStops,1);
for stop = 1:nStops
whichIdxs = outedges(G,stop); % Identify trips associated with the stop
constr2trips(stop) = sum(trips(whichIdxs)) == 2;
end
tsp.Constraints.constr2trips = constr2trips;
这样得到的结果大概率如下图所示,会有许多子回路。
子回路的个数通过如下进行计算:
tspsol = solve(tsp,'options',options)
tspsol.trips = logical(round(tspsol.trips))
Gsol = graph(idxs(tspsol.trips,1),idxs(tspsol.trips,2),[],numnodes(G));
tourIdxs = conncomp(Gsol)
numtours = max(tourIdxs); % Number of subtours
fprintf('# of subtours: %d\n',numtours);
如何消除子回路成为定义约束的关键问题。
额外的约束称为子回路消除约束。
子回路消除约束
由于无法在问题求解的一开始就找到子回路,子回路只能在通过上述朴素约束求解的基础上进行。
基本的思路是,找到上述基本解中的子回路,通过增加约束消除子回路。
如何消除子回路?举一个例子。如果一个子回路是5个节点组成的,这个子回路就有5条互联的边,增加的一个不等式约束为:这五个节点之间的边不能多于5.
推广得到:任意小于nSteps的集合若包含N个节点,则这N个节点包含的边不能多于N。
在迭代的过程中遇到一个子回路则添加上述的一个约束,直到最终只剩下1个子回路。代码如下所示。
figure
hGraph = plot(G,'XData',stopsLon,'YData',stopsLat,'LineStyle','none','NodeLabel',{});
hold on
% Draw the outside border
plot(x,y,'r-')
hold on
% Index of added constraints for subtours
k = 1;
while numtours > 1 % Repeat until there is just one subtour
% Add the subtour constraints
for ii = 1:numtours
inSubTour = (tourIdxs == ii); % Edges in current subtour
a = all(inSubTour(idxs),2); % Complete graph indices with both ends in subtour
constrname = "subtourconstr" + num2str(k);
tsp.Constraints.(constrname) = sum(trips(a)) <= (nnz(inSubTour) - 1);
k = k + 1;
end
% Try to optimize again
[tspsol,fval,exitflag,output] = solve(tsp,'options',options);
tspsol.trips = logical(round(tspsol.trips));
Gsol = graph(idxs(tspsol.trips,1),idxs(tspsol.trips,2),[],numnodes(G));
% Gsol = graph(idxs(tspsol.trips,1),idxs(tspsol.trips,2)); % Also works in most cases
% Plot new solution
hGraph.LineStyle = 'none'; % Remove the previous highlighted path
highlight(hGraph,Gsol,'LineStyle','-')
drawnow
% How many subtours this time?
tourIdxs = conncomp(Gsol);
numtours = max(tourIdxs); % Number of subtours
fprintf('# of subtours: %d\n',numtours)
fprintf('# total trip length: %f\n',fval)
end
title('Solution with Subtours Eliminated');
迭代过程如下图所示:
最终的约束如下所示。其中包含了41个消除子回路约束。
最终得到的结果如下图所示:
解的最优性说明见下节。