-
Notifications
You must be signed in to change notification settings - Fork 35
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
"Player 0x40ba72637962bbeb3da5c36780ff8adea7e9cdfb submitted 'clarke_…
…wright' for challenge vehicle_routing"
- Loading branch information
0x40ba72637962bbeb3da5c36780ff8adea7e9cdfb
committed
Apr 23, 2024
1 parent
768fa92
commit 7be15cc
Showing
2 changed files
with
88 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
use tig_challenges::vehicle_routing::*; | ||
|
||
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> { | ||
let d = &challenge.distance_matrix; | ||
let c = challenge.max_capacity; | ||
let n = challenge.difficulty.num_nodes; | ||
|
||
// Clarke-Wright heuristic for node pairs based on their distances to depot | ||
// vs distance between each other | ||
let mut scores: Vec<(i32, usize, usize)> = Vec::new(); | ||
for i in 1..n { | ||
for j in (i + 1)..n { | ||
scores.push((d[i][0] + d[0][j] - d[i][j], i, j)); | ||
} | ||
} | ||
scores.sort_by(|a, b| b.0.cmp(&a.0)); // Sort in descending order by score | ||
|
||
// Create a route for every node | ||
let mut routes: Vec<Option<Vec<usize>>> = (0..n).map(|i| Some(vec![i])).collect(); | ||
routes[0] = None; | ||
let mut route_demands: Vec<i32> = challenge.demands.clone(); | ||
|
||
// Iterate through node pairs, starting from greatest score | ||
for (s, i, j) in scores { | ||
// Stop if score is negative | ||
if s < 0 { | ||
break; | ||
} | ||
|
||
// Skip if joining the nodes is not possible | ||
if routes[i].is_none() || routes[j].is_none() { | ||
continue; | ||
} | ||
|
||
let left_route = routes[i].as_ref().unwrap(); | ||
let right_route = routes[j].as_ref().unwrap(); | ||
let mut left_startnode = left_route[0]; | ||
let right_startnode = right_route[0]; | ||
let left_endnode = left_route[left_route.len() - 1]; | ||
let mut right_endnode = right_route[right_route.len() - 1]; | ||
let merged_demand = route_demands[left_startnode] + route_demands[right_startnode]; | ||
|
||
if left_startnode == right_startnode || merged_demand > c { | ||
continue; | ||
} | ||
|
||
let mut left_route = routes[i].take().unwrap(); | ||
let mut right_route = routes[j].take().unwrap(); | ||
routes[left_startnode] = None; | ||
routes[right_startnode] = None; | ||
routes[left_endnode] = None; | ||
routes[right_endnode] = None; | ||
|
||
// reverse it | ||
if left_startnode == i { | ||
left_route.reverse(); | ||
left_startnode = left_endnode; | ||
} | ||
if right_endnode == j { | ||
right_route.reverse(); | ||
right_endnode = right_startnode; | ||
} | ||
|
||
let mut new_route = left_route; | ||
new_route.extend(right_route); | ||
|
||
// Only the start and end nodes of routes are kept | ||
routes[left_startnode] = Some(new_route.clone()); | ||
routes[right_endnode] = Some(new_route); | ||
route_demands[left_startnode] = merged_demand; | ||
route_demands[right_endnode] = merged_demand; | ||
} | ||
|
||
Ok(Some(Solution { | ||
routes: routes | ||
.into_iter() | ||
.enumerate() | ||
.filter(|(i, x)| x.as_ref().is_some_and(|x| x[0] == *i)) | ||
.map(|(_, mut x)| { | ||
let mut route = vec![0]; | ||
route.append(x.as_mut().unwrap()); | ||
route.push(0); | ||
route | ||
}) | ||
.collect(), | ||
})) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters