Search for the best solution
Here is a recursive approach to solving your problem.
Let's start with some definitions:
- Let A = (A i ) 1 β€ i β€ N be regions.
- Let w i, j = w j, i be the time cost for the transition from A i to A j and vice versa.
- Let r i be the reward for visiting the area A i
Here is a recursive procedure that will output the exact requested solution: (pseudocode)
List<Area> GetBestPath(int time_limit, Area S, int *rwd) { int best_reward(0), possible_reward(0), best_fit(0); List<Area> possible_path[N] = {[]}; if (time_limit < 0) { return []; } if (!S.visited) { *rwd += S.reward; S.visit(); } for (int i = 0; i < N; ++i) { if (S.index != i) { possible_path[i] = GetBestPath(time_limit - W[S.index][i], A[i], &possible_reward); if (possible_reward > best_reward) { best_reward = possible_reward; best_fit = i; } } } *rwd+= best_reward; possible_path[best_fit].push_front(S); return possible_path[best_fit]; }
For obvious clarity, I suggested that A i will be available worldwide, as well as w i, j .
Explanation
You start with S. The first thing you do? Collect the reward and mark the node as you visit. Then you need to check which path is best between neighbors S N-1 (allows you to call them N S, i for 1 β€ i β€ N-1).
This is the same as solving the problem for N S, i with a time limit:
time_limit - W (S β N S, i )
And since you mark the visited sites when you get into the area, you first check to see if it is checked. If so, you do not have a reward ... You also collect and mark it as you visited ...
Etc!
The final condition is when time_limit (C) becomes negative. This tells us that we have reached the limit and cannot move on: the recursion is complete. The final path may contain useless trips if all the rewards have been collected before reaching the limit C. You will have to "crop" the output list.
Complexity?
Oh, this decision is soooooooo terrible in terms of complexity! Each call leads to N-1 calls ... Until a deadline is reached. The longest possible sequence of calls is obtained with each call forward and backward along the shortest edge. Let w min be the weight of this edge.
Then, obviously, the overall complexity is bounded by N C / w min .C / w min .
This is huuuuuge.
Another approach
Maintain a hash table of all visited nodes. On the other hand, maintain a queue of maximum priority (for example, using MaxHeap) of nodes that are not yet assembled. (The top of the heap is the highest award node). The priority value for each node A i in the queue is set as a pair (r i , E [w i, j] )
- Put a bunch:
Target <- heap.pop() . - Calculate the shortest path to this node using Dijkstra's algorithm.
- Check the path: if the cost of the path is too high, then node is not available, add it to the list of inaccessible nodes.
- Else collect all the unsaved nodes that you find in it, and ...
- Remove each assembled node from the heap.
- Set your goal as a new starting point.
- In either case, go to step 1. until the heap is empty.
Note. A hash table is best for tracking collected nodes. Thus, we can check the node according to the path computed using Dijkstra in O (1).
Likewise, storing a hash table leading to the position of each node in the heap can be useful for optimizing heap pruning when collecting nodes along a path.
Small analysis
This approach is slightly better than the first in terms of complexity, but cannot lead to an optimal result. In fact, it may even work poorly on some graphics configurations. For example, if all nodes have a reward r, with the exception of one node T having r + 1 and W (N β T) = C for each node N, but other edges will be available to everyone, this will only make you collect T and skip all the rest of the node. In this particular case, the best solution would be to ignore T and collect all the others, which will result in a reward of (N-1). R instead of just r + 1.