What is the most efficient way of finding a path through a small world graph?
General notes
Dijkstra's algorithm and it optimised variant A* find the path with "the" minimal cost through your graph. The important things are a) defining your graph correctly and b) defining an appropriate cost function.
In the face of a changing cost function Dijksta requires one to re-calculate the solution.
For load-balancing I would extend Dikstra to not only calculate the optimal path, but use some kind of flood-fill behaviour to create a set of possible paths (sorted by cost) to find alternatives. Only knowledge about the specific problem and cost function can answer whether and how this might work.
Ant Colony Optimisation on the other hand seems to be much more flexible in adapting to a changing cost function, by continuing the iteration after/while the cost function changes.
Efficiency
This depends very much on your problem domain. If you have a good heuristic (see the Complexity section of the A* article) and seldom cost changes then A*'s polynomial runtime might favour repeated re-calculations. ACO on the other hand has to iterate over and over again before converging on an approximate solution. If cost changes occur very frequently, continuing the iteration at a constant rate might be more efficient than updating the A*-solution, since information is retained within the state of the algorithm. ACO doesn't promise the optimal solution, though and probably has higher start-up costs before converging onto a "good" solution. Again that very much depends on your specific domain, graph and cost function as well as your requirements on optimality.
Definitely A*. A* will either find the best path possible or no path at all if no path exists. E.g. the path of this boat has been calculated using A*
(source: cokeandcode.com)
Here's an interactive Java Demo to play with. Please note that this algorithm is slowed down by sleeps, so you see it performing. Without this slow down it would find the path in less than a second.
The algorithm is simple, yet powerful. Each node has 3 values, g is the cost up to this node. h is the estimated cost from this node to the target and f is the sum of both (it's a guess for the full path). A* maintains two lists, the Open and the Closed list. The Open list contains all nodes that have not been explored so far. The Closed list all nodes that have been explored. A node counts as explored if the algorithm has already tested every node connected to this node (connected could only mean horizontally and vertically, but also diagonal if diagonal moves between nodes are allowed).
The algorithm could be described as
- Let P be the starting point
- Assign g, h, and f values to P
- Add P to the open list (at this point P is the only node on that list).
- Let B be the best node from the Open list (best == lowest f value)
- If B is the goal node -> quit, you found the path
- If the Open list is empty -> quit, no path exists
- Let C be a valid node connected to B
- Assign g, h, and f to C
- Check if C is on the Open or Closed List
- If yes, check whether new path is most efficient (lower f-value)
- If so, update the path
- Else add C to the Open List
- If yes, check whether new path is most efficient (lower f-value)
- Repeat step 5 for all nodes connected to B
- Add B to the Closed list (we explored all neighbors)
- Repeat from step 4.
Also have a look at Wikipedia for implementation details.
With A*, the path cost does not need to be constant, so you could start with the following graph:
A---1---B---1---C
| |
\-------1-------/
where we want to go from A to C. Initially, the path finding algorithm will choose the A-C path since A-B-C is 2 whereas A-C is 1. We can add an extra term to the paths:
A---r---B---r---C
| |
\-------r-------/
with
r(NM) = k(NM) + users(NM) / 10
where
r(NM) is the cost for a connection between N and M,
k(NM) is the constant cost for a connection between N and M,
users(NM) is the number of objects using the connection
As users are added to the system, the route A-C will become more expensive than A-B-C at twenty users (1 + 20/10) = 3, A-B-C is 2. As users are removed from the system, the A-C route will become the best option again.
The real power of the A* is the heuristic you use to calculate the cost of each connection.
The most commonly used algorithm for this problem is A* (A Star), which is a generalized Dijkstra's algorithm search with added heuristics - the purpose of the heuristics is to direct the search towards the search goal so that typical searches finish faster.
This algorithm has many variants, derived versions and improvements, Google search or the Wikipedia page should be a good starting point.