result = new ArrayList<>(Collections.singletonList(1));//source node
99 | result.addAll(list.stream().map(aList -> aList + 1).collect(Collectors.toList()));
100 | return result;
101 | }
102 |
103 | }
104 |
105 |
--------------------------------------------------------------------------------
/VRP-GA/src/main/java/vrp/configuration/Node.java:
--------------------------------------------------------------------------------
1 | package vrp.configuration;
2 |
3 | public class Node {
4 | private int x;
5 | private int y;
6 | private int index;
7 | private int demand;
8 |
9 |
10 | Node(int x, int y, int index) {
11 | this(x, y, index, 0);
12 | }
13 |
14 | Node(final int x, final int y, final int index, final int demand) {
15 | this.x = x;
16 | this.y = y;
17 | this.demand = demand;
18 | this.index = index;
19 | }
20 |
21 | /**
22 | * Computes the euclidean distance between the current node and the given node
23 | *
24 | * @param node given node
25 | * @return distance from this to node
26 | */
27 | public double distanceTo(final Node node) {
28 | return Math.sqrt(Math.pow((node.x - this.x), 2) + Math.pow((node.y - this.y), 2));
29 | }
30 |
31 | public int getDemand() {
32 | return demand;
33 | }
34 |
35 |
36 | public int getIndex() {
37 | return index;
38 | }
39 |
40 | public void setDemand(int demand) {
41 | this.demand = demand;
42 | }
43 |
44 | @Override
45 | public String toString() {
46 | return "(" + this.x + ", " + this.y + ") - Demand: " + this.demand;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/VRP-GA/src/main/java/vrp/configuration/VrpConfiguration.java:
--------------------------------------------------------------------------------
1 | package vrp.configuration;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.IOException;
5 | import java.io.InputStreamReader;
6 | import java.util.Arrays;
7 |
8 | public class VrpConfiguration {
9 |
10 | private int numberOfTrucks;
11 | private int graphDimension;
12 | private int vehicleCapacity;
13 |
14 | private Node nodes[];
15 |
16 | public VrpConfiguration(final String file) throws IOException {
17 | try (final BufferedReader br = new BufferedReader(new InputStreamReader(this.getClass().getResourceAsStream(file)))) {
18 |
19 | String line;
20 |
21 | boolean demand = false;
22 |
23 | while ((line = br.readLine()) != null) {
24 | if (line.contains("DIMENSION")) {
25 | this.graphDimension = Integer.parseInt(line.split(":")[1].trim());
26 | this.nodes = new Node[graphDimension];
27 | } else if (line.contains("CAPACITY")) {
28 | vehicleCapacity = Integer.parseInt(line.split(":")[1].trim());
29 | break;
30 | }
31 | }
32 |
33 |
34 | br.readLine(); // this line is to jump the "NODE_COORD_SECTION" line
35 |
36 | int i = 0;
37 | while ((line = br.readLine()) != null) {
38 | if (line.contains("DEPOT_SECTION"))
39 | break;
40 | if (line.contains("DEMAND_SECTION")) {
41 | demand = true;
42 | i = 0;
43 | line = br.readLine();
44 | }
45 | if (!demand) {
46 | final String[] tokens = line.trim().split(" ");
47 | final int x = Integer.parseInt(tokens[1]);
48 | final int y = Integer.parseInt(tokens[2]);
49 | nodes[i] = new Node(x, y, i);
50 | i++;
51 | } else {
52 | nodes[i++].setDemand(Integer.parseInt(line.trim().split(" ")[1]));
53 | }
54 | }
55 | }
56 |
57 | this.numberOfTrucks = (int) Math.ceil(1.0 * getTotalDemand() / vehicleCapacity);
58 | }
59 |
60 | public VrpConfiguration(final String file, final int numberOfTrucks) throws IOException {
61 | this(file);
62 | this.numberOfTrucks = numberOfTrucks;
63 | }
64 |
65 |
66 | public int getNumberOfTrucks() {
67 | return numberOfTrucks;
68 | }
69 |
70 | public int getVehicleCapacity() {
71 | return vehicleCapacity;
72 | }
73 |
74 | public Node getNode(final int p) {
75 | return nodes[p];
76 | }
77 |
78 | public int getGraphDimension() {
79 | return graphDimension;
80 | }
81 |
82 | public int getTotalDemand() {
83 | return Arrays.stream(this.nodes).mapToInt(Node::getDemand).sum();
84 | }
85 |
86 | @Override
87 | public String toString() {
88 | final StringBuilder stringBuilder = new StringBuilder();
89 | stringBuilder.append("total number of nodes: ").append(this.graphDimension).append("\n");
90 | stringBuilder.append("capacity of vehicles: ").append(this.vehicleCapacity).append("\n");
91 | stringBuilder.append("number of vehicles: ").append(this.numberOfTrucks).append("\n");
92 | for (int i = 0; i < this.graphDimension; i++) {
93 | stringBuilder.append("Node ").append(i + 1).append(" ").append(this.nodes[i]).append("\n");
94 | }
95 | stringBuilder.append("total demanded: ").append(this.getTotalDemand()).append("\n");
96 | return stringBuilder.toString();
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/VRP-GA/src/main/java/vrp/evolution/VrpFitnessFunc.java:
--------------------------------------------------------------------------------
1 | package vrp.evolution;
2 |
3 | import org.jgap.FitnessFunction;
4 | import org.jgap.IChromosome;
5 | import vrp.configuration.Node;
6 | import vrp.configuration.VrpConfiguration;
7 |
8 | import java.util.ArrayList;
9 | import java.util.Collections;
10 | import java.util.List;
11 |
12 | public class VrpFitnessFunc extends FitnessFunction {
13 |
14 | private static final int PENALIZE_INCOMPLETE_DELIVERY = 125;
15 | private static final int PENALIZE_INCOMPLETE_TRUCK = 2;
16 | private static final int PENALIZE_DISTANCE = 25;
17 | private final VrpConfiguration vrpConfiguration;
18 |
19 | public VrpFitnessFunc(final VrpConfiguration conf) {
20 | this.vrpConfiguration = conf;
21 | }
22 |
23 | /**
24 | * Computes the fitness of the chromosome
25 | * - total_distance = distance covered by a vehicle
26 | * - total_demand = demand covered by solution:
27 | * - 25 * (covered_demand - vehicle_capacity) - the truck can't deliver everything
28 | * - 2 * (vehicle_capacity - covered_demand) - the truck has unused capacity
29 | *
30 | * fitness = 10 * total_distance + total_demand
31 | *
32 | * Constraints
33 | * 1<=fitness<=1000000
34 | *
35 | * @param chromosome given chromosome
36 | * @return fitness value of the chromosome
37 | */
38 | @Override
39 | public double evaluate(final IChromosome chromosome) {
40 | final int numberOfVehicles = this.vrpConfiguration.getNumberOfTrucks();
41 | double fitness = 0;
42 |
43 | for (int i = 1; i <= numberOfVehicles; i++) {
44 | fitness += computeTotalDistance(i, chromosome, vrpConfiguration) * PENALIZE_DISTANCE;
45 | fitness += computeTotalDemand(i, chromosome, vrpConfiguration);
46 | }
47 |
48 | if (fitness < 0) {
49 | return 0;
50 | }
51 |
52 | return Math.max(1, 1000000 - fitness);
53 | }
54 |
55 | public static double computeTotalCoveredDemand(int vehicleNumber, IChromosome chromosome, VrpConfiguration vrpConfiguration) {
56 | final List positions = getPositions(vehicleNumber, chromosome, vrpConfiguration, false);
57 |
58 |
59 | double totalCoveredBySolution = 0.0;
60 | for (int pos : positions) {
61 | final Node node = vrpConfiguration.getNode(pos);
62 | totalCoveredBySolution += node.getDemand();
63 | }
64 |
65 | return totalCoveredBySolution;
66 | }
67 |
68 | private static double computeTotalDemand(int vehicleNumber, IChromosome chromosome, VrpConfiguration vrpConfiguration) {
69 | final double totalCoveredBySolution = computeTotalCoveredDemand(vehicleNumber, chromosome, vrpConfiguration);
70 | final double vehicleCapacity = vrpConfiguration.getVehicleCapacity();
71 |
72 | if (totalCoveredBySolution > vehicleCapacity) {//can't complete delivery
73 | return (totalCoveredBySolution - vehicleCapacity) * PENALIZE_INCOMPLETE_DELIVERY;
74 | }
75 | return (vehicleCapacity - totalCoveredBySolution) * PENALIZE_INCOMPLETE_TRUCK;//unused capacity
76 | }
77 |
78 | public static double computeTotalDistance(int vehicleNumber, IChromosome chromosome, VrpConfiguration vrpConfiguration) {
79 | double totalDistance = 0.0;
80 | final List positions = getPositions(vehicleNumber, chromosome, vrpConfiguration, true);
81 |
82 | final Node store = vrpConfiguration.getNode(0);//first node represents the starting point
83 |
84 | Node lastVisited = store;
85 |
86 | for (int pos : positions) {
87 | final Node node = vrpConfiguration.getNode(pos);
88 | totalDistance += lastVisited.distanceTo(node);
89 | lastVisited = node;
90 | }
91 |
92 | totalDistance += lastVisited.distanceTo(store);//distance back to the store
93 |
94 | return totalDistance;
95 | }
96 |
97 |
98 | /**
99 | * Reads data from the given chromosome in order
100 | * to generate the solution representing the
101 | * order of nodes for a vehicle
102 | *
103 | * @param vehicleNumber given vehicle
104 | * @param chromosome to be decoded
105 | * @param configuration existing configuration
106 | * @param order if nodes need to be sorted
107 | * @return sequence of nodes representing the track of the given vehicle
108 | */
109 | public static List getPositions(final int vehicleNumber, final IChromosome chromosome, final VrpConfiguration configuration, final boolean order) {
110 | final List route = new ArrayList<>();
111 | final List positions = new ArrayList<>();
112 | final int graphDimension = configuration.getGraphDimension();
113 | for (int i = 1; i < graphDimension; ++i) {
114 | int chromosomeValue = (Integer) chromosome.getGene(i).getAllele();
115 | if (chromosomeValue == vehicleNumber) {
116 | route.add(i);
117 | positions.add((Double) chromosome.getGene(i + graphDimension).getAllele());
118 | }
119 | }
120 |
121 | if (order) {
122 | order(positions, route);
123 | }
124 |
125 | return route;
126 |
127 | }
128 |
129 |
130 | private static void order(List positions, List route) {
131 | for (int i = 0; i < positions.size(); ++i) {//todo improve sorting
132 | for (int j = i + 1; j < positions.size(); ++j) {
133 | if (positions.get(i).compareTo(positions.get(j)) < 0) {
134 | Collections.swap(positions, i, j);
135 | Collections.swap(route, i, j);
136 | }
137 | }
138 | }
139 | }
140 |
141 |
142 | }
143 |
--------------------------------------------------------------------------------
/VRP-GA/src/main/resources/A-n45-k6-in.txt:
--------------------------------------------------------------------------------
1 | NAME : A-n45-k6
2 | COMMENT : (Augerat et al, No of trucks: 6, Optimal value: 944)
3 | TYPE : CVRP
4 | DIMENSION : 45
5 | EDGE_WEIGHT_TYPE : EUC_2D
6 | CAPACITY : 100
7 | NODE_COORD_SECTION
8 | 1 31 73
9 | 2 11 67
10 | 3 52 96
11 | 4 81 29
12 | 5 97 62
13 | 6 71 5
14 | 7 6 56
15 | 8 48 50
16 | 9 91 17
17 | 10 49 68
18 | 11 85 29
19 | 12 11 16
20 | 13 74 98
21 | 14 56 37
22 | 15 13 81
23 | 16 66 80
24 | 17 96 55
25 | 18 36 17
26 | 19 32 23
27 | 20 6 13
28 | 21 64 30
29 | 22 87 5
30 | 23 75 61
31 | 24 40 72
32 | 25 1 44
33 | 26 60 95
34 | 27 27 49
35 | 28 15 33
36 | 29 46 53
37 | 30 28 43
38 | 31 3 9
39 | 32 1 100
40 | 33 53 46
41 | 34 98 8
42 | 35 6 25
43 | 36 7 81
44 | 37 96 88
45 | 38 2 35
46 | 39 32 94
47 | 40 95 94
48 | 41 9 11
49 | 42 96 16
50 | 43 90 68
51 | 44 33 31
52 | 45 6 59
53 | DEMAND_SECTION
54 | 1 0
55 | 2 19
56 | 3 2
57 | 4 12
58 | 5 20
59 | 6 6
60 | 7 17
61 | 8 8
62 | 9 14
63 | 10 2
64 | 11 8
65 | 12 5
66 | 13 7
67 | 14 22
68 | 15 14
69 | 16 17
70 | 17 23
71 | 18 15
72 | 19 21
73 | 20 2
74 | 21 24
75 | 22 10
76 | 23 20
77 | 24 6
78 | 25 21
79 | 26 10
80 | 27 6
81 | 28 13
82 | 29 21
83 | 30 24
84 | 31 11
85 | 32 16
86 | 33 8
87 | 34 11
88 | 35 11
89 | 36 22
90 | 37 17
91 | 38 22
92 | 39 17
93 | 40 8
94 | 41 23
95 | 42 5
96 | 43 3
97 | 44 18
98 | 45 12
99 | DEPOT_SECTION
100 | 1
101 | -1
102 | EOF
103 |
--------------------------------------------------------------------------------
/VRP-GA/src/main/resources/A-n45-k6-out.txt:
--------------------------------------------------------------------------------
1 | Route #1: 1 19 18 12 41 31 20 35 45 (D=100)
2 | Route #2: 1 30 44 14 8 29 24 (D=99)
3 | Route #3: 1 33 21 6 22 34 42 9 11 4 (D=98)
4 | Route #4: 1 13 40 37 43 5 17 23 10 (D=100)
5 | Route #5: 1 27 28 38 25 7 2 (D=98)
6 | Route #6: 1 16 26 3 39 32 36 15 (D=98)
7 | cost 944
8 |
9 |
--------------------------------------------------------------------------------
/VRP-GA/src/main/resources/A-n60-k9-in.txt:
--------------------------------------------------------------------------------
1 | NAME : A-n60-k9
2 | COMMENT : (Augerat et al, No of trucks: 9, Optimal value: 1354)
3 | TYPE : CVRP
4 | DIMENSION : 60
5 | EDGE_WEIGHT_TYPE : EUC_2D
6 | CAPACITY : 100
7 | NODE_COORD_SECTION
8 | 1 27 93
9 | 2 33 27
10 | 3 29 39
11 | 4 7 81
12 | 5 1 59
13 | 6 49 9
14 | 7 21 53
15 | 8 79 89
16 | 9 81 83
17 | 10 85 11
18 | 11 45 9
19 | 12 7 65
20 | 13 95 27
21 | 14 81 85
22 | 15 37 81
23 | 16 69 69
24 | 17 15 95
25 | 18 89 75
26 | 19 33 93
27 | 20 57 83
28 | 21 11 95
29 | 22 3 57
30 | 23 45 11
31 | 24 43 61
32 | 25 35 43
33 | 26 19 83
34 | 27 83 69
35 | 28 85 77
36 | 29 19 39
37 | 30 83 87
38 | 31 1 13
39 | 32 15 39
40 | 33 83 17
41 | 34 41 97
42 | 35 31 61
43 | 36 59 69
44 | 37 29 15
45 | 38 93 83
46 | 39 63 97
47 | 40 65 57
48 | 41 15 69
49 | 42 31 97
50 | 43 57 9
51 | 44 85 37
52 | 45 21 29
53 | 46 53 11
54 | 47 15 77
55 | 48 41 69
56 | 49 45 17
57 | 50 13 25
58 | 51 63 57
59 | 52 95 5
60 | 53 55 91
61 | 54 3 31
62 | 55 47 7
63 | 56 61 69
64 | 57 85 35
65 | 58 89 81
66 | 59 45 47
67 | 60 65 93
68 | DEMAND_SECTION
69 | 1 0
70 | 2 16
71 | 3 2
72 | 4 7
73 | 5 11
74 | 6 9
75 | 7 17
76 | 8 21
77 | 9 23
78 | 10 10
79 | 11 6
80 | 12 19
81 | 13 18
82 | 14 20
83 | 15 13
84 | 16 5
85 | 17 11
86 | 18 24
87 | 19 2
88 | 20 3
89 | 21 1
90 | 22 5
91 | 23 20
92 | 24 23
93 | 25 24
94 | 26 18
95 | 27 19
96 | 28 2
97 | 29 17
98 | 30 17
99 | 31 9
100 | 32 11
101 | 33 2
102 | 34 6
103 | 35 9
104 | 36 5
105 | 37 9
106 | 38 2
107 | 39 14
108 | 40 19
109 | 41 11
110 | 42 21
111 | 43 20
112 | 44 21
113 | 45 18
114 | 46 48
115 | 47 1
116 | 48 17
117 | 49 42
118 | 50 2
119 | 51 4
120 | 52 24
121 | 53 18
122 | 54 21
123 | 55 11
124 | 56 9
125 | 57 18
126 | 58 22
127 | 59 9
128 | 60 23
129 | DEPOT_SECTION
130 | 1
131 | -1
132 | EOF
133 |
--------------------------------------------------------------------------------
/VRP-GA/src/main/resources/A-n60-k9-out.txt:
--------------------------------------------------------------------------------
1 | Route #1: 2 1 48 22 36 31
2 | Route #2: 4 21 53 30 49 44 28 6
3 | Route #3: 7 29 13 8 15 55 35
4 | Route #4: 10 54 5 45 42
5 | Route #5: 14 47 23 58 24 34
6 | Route #6: 16 20 3 11 40 46 25
7 | Route #7: 18 52 59 38 33 41
8 | Route #8: 19 27 57 37 17 26 39
9 | Route #9: 32 9 51 12 56 43 50
10 | cost 1354
11 |
--------------------------------------------------------------------------------
/VRP-GA/target/classes/A-n45-k6-in.txt:
--------------------------------------------------------------------------------
1 | NAME : A-n45-k6
2 | COMMENT : (Augerat et al, No of trucks: 6, Optimal value: 944)
3 | TYPE : CVRP
4 | DIMENSION : 45
5 | EDGE_WEIGHT_TYPE : EUC_2D
6 | CAPACITY : 100
7 | NODE_COORD_SECTION
8 | 1 31 73
9 | 2 11 67
10 | 3 52 96
11 | 4 81 29
12 | 5 97 62
13 | 6 71 5
14 | 7 6 56
15 | 8 48 50
16 | 9 91 17
17 | 10 49 68
18 | 11 85 29
19 | 12 11 16
20 | 13 74 98
21 | 14 56 37
22 | 15 13 81
23 | 16 66 80
24 | 17 96 55
25 | 18 36 17
26 | 19 32 23
27 | 20 6 13
28 | 21 64 30
29 | 22 87 5
30 | 23 75 61
31 | 24 40 72
32 | 25 1 44
33 | 26 60 95
34 | 27 27 49
35 | 28 15 33
36 | 29 46 53
37 | 30 28 43
38 | 31 3 9
39 | 32 1 100
40 | 33 53 46
41 | 34 98 8
42 | 35 6 25
43 | 36 7 81
44 | 37 96 88
45 | 38 2 35
46 | 39 32 94
47 | 40 95 94
48 | 41 9 11
49 | 42 96 16
50 | 43 90 68
51 | 44 33 31
52 | 45 6 59
53 | DEMAND_SECTION
54 | 1 0
55 | 2 19
56 | 3 2
57 | 4 12
58 | 5 20
59 | 6 6
60 | 7 17
61 | 8 8
62 | 9 14
63 | 10 2
64 | 11 8
65 | 12 5
66 | 13 7
67 | 14 22
68 | 15 14
69 | 16 17
70 | 17 23
71 | 18 15
72 | 19 21
73 | 20 2
74 | 21 24
75 | 22 10
76 | 23 20
77 | 24 6
78 | 25 21
79 | 26 10
80 | 27 6
81 | 28 13
82 | 29 21
83 | 30 24
84 | 31 11
85 | 32 16
86 | 33 8
87 | 34 11
88 | 35 11
89 | 36 22
90 | 37 17
91 | 38 22
92 | 39 17
93 | 40 8
94 | 41 23
95 | 42 5
96 | 43 3
97 | 44 18
98 | 45 12
99 | DEPOT_SECTION
100 | 1
101 | -1
102 | EOF
103 |
--------------------------------------------------------------------------------
/VRP-GA/target/classes/A-n45-k6-out.txt:
--------------------------------------------------------------------------------
1 | Route #1: 1 19 18 12 41 31 20 35 45 (D=100)
2 | Route #2: 1 30 44 14 8 29 24 (D=99)
3 | Route #3: 1 33 21 6 22 34 42 9 11 4 (D=98)
4 | Route #4: 1 13 40 37 43 5 17 23 10 (D=100)
5 | Route #5: 1 27 28 38 25 7 2 (D=98)
6 | Route #6: 1 16 26 3 39 32 36 15 (D=98)
7 | cost 944
8 |
9 |
--------------------------------------------------------------------------------
/VRP-GA/target/classes/A-n60-k9-in.txt:
--------------------------------------------------------------------------------
1 | NAME : A-n60-k9
2 | COMMENT : (Augerat et al, No of trucks: 9, Optimal value: 1354)
3 | TYPE : CVRP
4 | DIMENSION : 60
5 | EDGE_WEIGHT_TYPE : EUC_2D
6 | CAPACITY : 100
7 | NODE_COORD_SECTION
8 | 1 27 93
9 | 2 33 27
10 | 3 29 39
11 | 4 7 81
12 | 5 1 59
13 | 6 49 9
14 | 7 21 53
15 | 8 79 89
16 | 9 81 83
17 | 10 85 11
18 | 11 45 9
19 | 12 7 65
20 | 13 95 27
21 | 14 81 85
22 | 15 37 81
23 | 16 69 69
24 | 17 15 95
25 | 18 89 75
26 | 19 33 93
27 | 20 57 83
28 | 21 11 95
29 | 22 3 57
30 | 23 45 11
31 | 24 43 61
32 | 25 35 43
33 | 26 19 83
34 | 27 83 69
35 | 28 85 77
36 | 29 19 39
37 | 30 83 87
38 | 31 1 13
39 | 32 15 39
40 | 33 83 17
41 | 34 41 97
42 | 35 31 61
43 | 36 59 69
44 | 37 29 15
45 | 38 93 83
46 | 39 63 97
47 | 40 65 57
48 | 41 15 69
49 | 42 31 97
50 | 43 57 9
51 | 44 85 37
52 | 45 21 29
53 | 46 53 11
54 | 47 15 77
55 | 48 41 69
56 | 49 45 17
57 | 50 13 25
58 | 51 63 57
59 | 52 95 5
60 | 53 55 91
61 | 54 3 31
62 | 55 47 7
63 | 56 61 69
64 | 57 85 35
65 | 58 89 81
66 | 59 45 47
67 | 60 65 93
68 | DEMAND_SECTION
69 | 1 0
70 | 2 16
71 | 3 2
72 | 4 7
73 | 5 11
74 | 6 9
75 | 7 17
76 | 8 21
77 | 9 23
78 | 10 10
79 | 11 6
80 | 12 19
81 | 13 18
82 | 14 20
83 | 15 13
84 | 16 5
85 | 17 11
86 | 18 24
87 | 19 2
88 | 20 3
89 | 21 1
90 | 22 5
91 | 23 20
92 | 24 23
93 | 25 24
94 | 26 18
95 | 27 19
96 | 28 2
97 | 29 17
98 | 30 17
99 | 31 9
100 | 32 11
101 | 33 2
102 | 34 6
103 | 35 9
104 | 36 5
105 | 37 9
106 | 38 2
107 | 39 14
108 | 40 19
109 | 41 11
110 | 42 21
111 | 43 20
112 | 44 21
113 | 45 18
114 | 46 48
115 | 47 1
116 | 48 17
117 | 49 42
118 | 50 2
119 | 51 4
120 | 52 24
121 | 53 18
122 | 54 21
123 | 55 11
124 | 56 9
125 | 57 18
126 | 58 22
127 | 59 9
128 | 60 23
129 | DEPOT_SECTION
130 | 1
131 | -1
132 | EOF
133 |
--------------------------------------------------------------------------------
/VRP-GA/target/classes/A-n60-k9-out.txt:
--------------------------------------------------------------------------------
1 | Route #1: 2 1 48 22 36 31
2 | Route #2: 4 21 53 30 49 44 28 6
3 | Route #3: 7 29 13 8 15 55 35
4 | Route #4: 10 54 5 45 42
5 | Route #5: 14 47 23 58 24 34
6 | Route #6: 16 20 3 11 40 46 25
7 | Route #7: 18 52 59 38 33 41
8 | Route #8: 19 27 57 37 17 26 39
9 | Route #9: 32 9 51 12 56 43 50
10 | cost 1354
11 |
--------------------------------------------------------------------------------