MODEL:
! (Dial_a_Ride) The traveling salesperson problem with the additional
condition that certain pairs of stops must be visited in a given order.
Specifically, for i even, stop i must be visited before stop i+1.
The interpretation is that someone is to be picked up at i and later
dropped off at i+1. The vehicle has sufficient capacity so that it
can carry as many people as necessary.
Stop 1 is the home base where no one is picked up and no one is dropped off;
! Keywords: Dial-a-ride, TSP, Traveling sales person, Routing, Tour, Sequencing;
SETS:
CITY: U; ! U( I) = sequence no. of city;
LINK( CITY, CITY):
DIST, ! The distance matrix;
X; ! X( I, J) = 1 if link I, J is in tour;
ENDSETS DATA: ! Distance matrix, it need not be symmetric;
CITY=
1..15;
DIST=
0 69 39 49 5 59 19 40 33 81 9 21 8 37 33
69 0 47 39 54 9 49 59 95 47 98 87 69 36 67
41 47 0 90 67 63 4 49 93 48 7 94 52 19 41
49 39 90 0 21 60 56 80 12 69 54 52 33 99 2
5 54 67 21 0 32 22 61 85 47 56 75 59 42 63
59 9 63 60 32 0 58 46 43 3 33 65 69 80 37
19 49 4 56 22 58 0 82 97 15 78 82 64 33 26
37 59 49 80 61 46 82 0 8 86 1 90 37 0 42
33 95 93 12 85 43 97 8 0 63 34 81 21 56 0
82 47 48 69 47 3 15 86 63 0 88 69 33 47 90
9 98 7 54 56 33 78 1 34 88 0 77 63 87 57
21 87 94 52 75 65 82 90 81 69 77 0 46 30 63
8 69 52 33 59 69 64 37 21 33 63 46 0 59 95
38 36 21 99 42 80 33 0 56 47 87 30 59 0 40
33 67 41 2 63 40 26 42 0 90 57 63 95 40 0;
ENDDATA
!-----------------------------------------------------------;
! Warning: May take long to solve cases with N >> 12;
! Variables:
X(i,j) = 1 if vehicle tour includes link from i to j, else 0,
U(i) = sequence number of stop i on the tour, or also
load on vehicle upon departing stop i. One unit of
load is picked up at each stop. Starts empty at stop 1;
N = @SIZE( CITY);
! Minimize total distance traveled;
MIN = @SUM( LINK(i,j): DIST(i,j) * X(i,j));
! Stop k must be entered exactly once;
! For k = 1, we return to 1 only from an odd numbered (drop off) stop;
@SUM( CITY(i) | @mod(i,2) #NE# 0 #and# i #NE# 1: x(i,1)) = 1;
@SUM( CITY(i) | @mod(i,2) #EQ# 0 : x(i,1)) = 0;
@FOR( CITY(k) | k #GT# 1:
@SUM( CITY( i)| i #NE# k: X( i, k)) = 1;
);
! Stop k must be departed exactly once;
! For k = 1, we go first to an even numbered (pick up) stop;
@SUM( CITY(j) | @mod(j,2) #EQ# 0 : x(1,j)) = 1;
@SUM( CITY(j) | @mod(j,2) #NE# 0 : x(1,j)) = 0;
@FOR( CITY(k) | k #GT# 1:
@SUM( CITY( j)| j #NE# k: X( k, j)) = 1;
X( k, k) = 0; ! Cannot go from k to k;
);
U(1) = 0; ! Start empty;
! A weak but simple form of the subtour breaking constraints,
see Desrochers & Laporte, OR Letters, Feb. 91.
Not very powerful for large(N>12) problems;
! Enforce:
If x(i,j) = 1 then U(j) - U(i) = 1,
If x(j,i) = 1 then U(j) - U(i) = -1,
If x(i,j) + x(j,i) = 0, and i,j > 1,
then U(j) - U(i) >= -(N - 2);
! The case either i or j = 1;
@FOR( CITY(i) | i #GT# 1:
U(i) >= 2 - X(1,i) + (N-3)*X(i,1);
U(i) <= (N-2) + X(i,1) - (N-3)*X(1,i);
);
! The case i,j > 1,
! This constraint, plus its "mirror", when i and j are switched,
forces U(j) - U(i) = 1 if X(i,j) = 1;
@FOR( LINK(i,j)| i #GT# 1 #AND# j #GT# 1 #AND# i #NE# j:
U( j) >= U( i) + X(i,j)
- X(j,i)
- (N-2)*(1 - X(i,j) - X(j,i));
);
! Make the X's 0/1;
@FOR( LINK(i,j): @BIN( X(i,j)););
! The dial-a-ride feature. Every pickup occurs before its dropoff;
@FOR(CITY(i) | @mod(i,2)#EQ#0 : U(i) <= U(i+1));
! Some cuts;
! We know the sum of the stop numbers;
@SUM( CITY( i): U( i)) = ( N-1)*N/2;
|