fix: replace O(N*K*N) BFS with multi-source Dijkstra in KMeansClustering#26
Open
ToB213 wants to merge 1 commit intoroborescue:masterfrom
Open
fix: replace O(N*K*N) BFS with multi-source Dijkstra in KMeansClustering#26ToB213 wants to merge 1 commit intoroborescue:masterfrom
ToB213 wants to merge 1 commit intoroborescue:masterfrom
Conversation
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #25.
This PR addresses two bugs in
KMeansClustering.calcPathBased()that together made precompute unusable on standard competition maps.Changes
Bug 1: Replace O(R·N·K·N) BFS with multi-source Dijkstra
The original implementation assigned each entity to its nearest center by calling
comparePathDistance()for every candidate center. This ran an uncached BFS (O(N)) twice per comparison, resulting in O(R·N·K·N) total complexity.This PR replaces that with
assignByMultiSourceDijkstra(), which seeds all K centers into a priority queue simultaneously and expands them using edge-weighted Dijkstra. Each entity is assigned to the center with the minimum path distance in a single O(N log N) pass.To support edge-weighted search,
initShortestPath()(unweighted adjacency graph) is replaced byinitWeightedGraph(). Edge weights are defined as:This matches the per-edge cost used in
getPathDistance(), so the resulting cluster assignments are equivalent to the original intended path-distance Voronoi partition.Bug 2: Guard against division by zero on empty clusters
When a cluster receives no entities, the division by
clusterEntitiesList.get(index).size()throwsArithmeticException.An
isEmpty()guard is added before the division in bothcalcPathBased()andcalcStandard().Note: the multi-source Dijkstra fix also eliminates this problem structurally for connected graphs, since every reachable entity is guaranteed to be assigned. The
isEmpty()guard remains as a defensive measure.Cleanup
initShortestPath(),shortestPathGraph, and the twogetNearEntity()overloads that became dead codeLazyMap,HashSet,SetshortestPath()(used bygetNearAgent()) now reusesweightedGraph.keySet()as its adjacency listVerified
Tested on the RSL 2025 kobe1 map (N=2,359, K=30, R=7) with the default agent configuration (30 PF / 30 FB / 30 AT).
ArithmeticExceptionimmediately; remaining agents did not complete and were manually killed after 6 minutes