I am tasked with programming an A* Search Algorithm for an assignment that involves solving an '8-Puzzle'.
One of the algorithm's steps is to:
Add all the extended paths to Q. If the descendant state is already in Q, keep only the shorter path to state in Q (where Q is a Priority Queue (PQ)).
As such, I will need to search the PQ if an identical state exists but has a shorter path. If an identical state already exists but it has a longer path, I will need to delete this state from the PQ.
I have been directed to use an STL PQ, not my own implementation. I have managed to implement other types of searches using the below to create a Min PQ - which works as desired.
auto cmp = [](Puzzle* a, Puzzle* b) {
return a->getHCost() > b->getHCost();
};
std::priority_queue<Puzzle*, std::vector<Puzzle*>, decltype(cmp)> Q(cmp);
How can I extend my implementation so that...
I can perform a brute force search - looping through each element of the STL PQ?
I can delete an element somewhere in the STL PQ by its index? - shuffling elements 'upwards' if appropriate.
You could have a secondary array named shortest[] where shortest[i] would be the shortest known path to the state i. Then whenever you get in the top of the PQ an element with state x, you check shortest[x] if it is indeed the shortest found and do whatever you want to it, else delete the element from the top of the PQ.
However, given that the states are from an 8-puzzle, you'd have to come up with an efficient way to give them a unique identifying number and ability to get it back efficiently.
It is possible to do both such things in O(1). I'm not sure if I should spoil my personal idea yet, given it is after all an assignment and you should undertake such a challenge.
Related
I am trying to figure out a way to implement a DFS search to find the length of the longest path from a given node on a directed graph represented as an adjacency list by using a stack, and not using recursion. Specifically, I want to implement the DFS search so that as it runs, the stack gets populated as shown in the picture below..
If that isn't clear, this video is sort of how I want the stack to be built up as my program runs (DFS starts at around 12:45 : https://www.youtube.com/watch?v=pcKY4hjDrxk
But im struggling to find a way to achieve this, as I am still pretty new to programming in general. My current code represents the graph as an unordered map, with each entry containing a vector of all the nodes that point to it. i.e:
std::unordered_map<long, std::vector<long>> nodes;
And basically, I want to implement a DFS search from all nodes with a key value of -1 in that unordered_map as shown in the picture and in the video- with the stack getting allocated as shown. I was thinking, that way I can just record when the stack reaches its maximum size, and that would be the longest path.
One thing to note is the graphs in this specific problem is that each edge will only have one outgoing degree, as shown in the picture.. Is this possible, or will I have to use some sort of recursion to do what I want? Thanks in advance for any help.
You can probably use a task list instead of recursion. If you use the task list in FIFO order like a queue, you get a breadth-first search; if you use it LIFO like a stack, you get depth-first behavior.
However, note that it is possible for a DAG with N nodes to have O(2^(N/2)) possible paths! You should not need to evaluate all possible paths to solve your problem, though, so be careful not to write an algorithm that can take exponential time.
In order to do that, you will need to mark which nodes you have processed. Also, since you are looking for the longest path, you'll need to track per-node information about the longest path found so far.
Although it's possible to achieve this without recursion, as an alternative, I would suggest you to design a function this way, which requires you to write less code and which will provide the nice intuition to understand this algorithm for you're a beginner. And you'll not need to think about creating stack by your own
const int n = 100;
vector< int > graph[n];
int ans = 0, level = 0;
int vis[n];
void dfs(int src) {
level++;
ans = max(level, ans);
for (int x: graph[src]) {
if(vis[x]) continue;
vis[x] = 1;
dfs(x);
level--;
}
}
I hard coded the value of n and graph you can change it as you need as required structure.
Where we take the advantages of the stack created for the recursion tree by the program.
This function will work in O(V+E) for a given graph of V nodes and E edges.
Note that, if your Graph is so large that the stack created default by the program can't handle, then you still have to write your own stack to handle the recursion.
I have found some similar questions on this subject, but I wanted to ask again in order to get a more clear answer. I am writing a graph matching algorithm, where each node on the graph assigned to a priority set depending on the matching of its neighbours. Details are not really important, but I am using an std::priority_queue in order to match the highest priority nodes first. Here is the tricky point: Each time a new match is introduced, the priority of the neighbours of the matching nodes shall be updated.
This algorithm is referenced from a paper and although I have implemented the exact same algorithm, I couldn't reach the same matching percentage. I naturally suspected that std::priority_queue may not be reordered as I wanted on priority updates, so I have run some tests and then I found out other questions asking the same thing:
How to tell a std::priority_queue to refresh its ordering?
Does changing a priority queue element result in resorting the queue?
My question naturally is, how can I update the order on new matchings? Can I enforce it? Or is there any other data structure (max heap for example) that can serve to this purpose? Note that, pushing new elements into the queue is not a valid solution for me. Here is the code piece I am using (matchFace() function updates the element priorities):
while (priorityQueue.size() != 0) {
// Take the face at the top of the queue and check if it is already matched
FaceData* currentFace = priorityQueue.top();
// Pop the face at the top in any case
priorityQueue.pop();
// If the face is not already matched, try to find a matching
if (!currentFace->matched) {
// Try to match the face with one of its neighbors, add it to the unmatched faces list if it fails
int neighborId = matchFace(currentFace);
if (neighborId == -1) {
unmatchedFaces.push_back(currentFace);
} else {
matchingMap[currentFace->id] = neighborId;
}
}
}
Using the comments that I received on the problem, I decided to answer it myself. I found out there are three possible ways to overcome this problem:
Implement your own updatable priority queue or use external libraries. Boost might have some additional data structures for this purpose. I also found an Updatable Priority Queue source code here.
Use a vector to store the values and use std::make_heap function provided in the algorithm library each time an update is received. This is the easiest way but it works very slow.
Remove and re-insert the elements. If this is not a valid approach, use a map to store the element ids and instead of removing the elements, mark the elements on the map so if you encounter them multiple times you can just ignore them. An alternative strategy is to alter the items by adding a flag and marking the elements by turning the flag on.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I was asked to implement a stack that pops the most frequently added item in an interview. I gave him the below answer but he was not happy with the solution.
class stack
{
// Map of value and count
map<int,int> Cntmap;
public:
void push(int val)
{
// Find val in map
// if found then increment map count
// else insert a pair (val,1)
}
int pop( )
{
// Find the Key in Cntmap with max value
// using std::max_element
// Decrement the Cntmap count for the popped val
}
}
Can anyone help me with the correct approach?
It's an interesting question, because in push, you look up
using the key, and in pop, using the mapped value. std::map
supports the first immediately: all you have to do is:
++ CntMap[ val ];
The [] operator will insert an entry if the key isn't
present, initializing the mapped type with its default
constructor, which for an int results in 0. You don't even
need the if.
The second is more difficult. The comments, however, give the
solution: all you need is a custom Compare, which takes two
std::pair<int, int>, and compares the second element.
std::max_element will return an iterator to the entry you're
interested in, so you can use it directly. So far so good (and
very simple), but you have to consider error conditions: what
happens if Cntmap is empty. And you might want to remove the
element if the count goes down to 0 (again, simple, since you
have an iterator designating the entry, with both the key and
the value).
Finally, if this is an interview question, I would definitly
point out that the pop operation is O(n), and that it might
be worthwhile (although significantly more complicated) to
maintain a secondary index, so that I could find the maximum
element more quickly. (If I were interviewing, that would be my
next question. Clearly for advanced programmers, however.)
The problem with only using a single (simple) data structure is that one of the operations will have to be linear (it has to search through all the elements), which is not good enough. In your case, I believe the linear-time operation is pop.
My attempt:
Have a linked-list (which will be ordered by frequency).
Have a map of values to nodes in the linked-list.
To push, look up the value in the map to get the linked-list node.
If found, increment the frequency and move the node appropriately to keep the linked-list sorted.
If not found, set the frequency to one and insert into the linked-list in the appropriate place.
To pop, decrement the frequency of first node of the linked-list and move it appropriately to keep the linked-list sorted, and return the applicable value.
You could have some pretty bad worst-case behaviour if there are many nodes with the same frequency. It should be possible to get constant time add / increment / decrement by having some sort of linked-list of linked-lists, with each node in the large linked-list representing a specific frequency and each linked-list from there representing all nodes having that frequency.
With the above optimization, pop can be O(1) and push can be O(log n). If you use an unordered_map (C++11), push can be O(1).
Another (probably slightly simpler) option is to do something similar to the above, but with a heap instead of a linked-list.
I think instead of a Map, Max-Heap will be better in your case. You can maintain a counter in a similar way. Note that the key of the heap will be the count rather than the actual value itself. When you have to insert a value, search for that value, if found, increment it's key, else, insert the value with key as 1.
Hope this helps.
The solution could be to wrap Boost.Bimap (does the organisation uses boost?). With this you could create a container which gives ordered access in one direction and hashed in the other. Your implementation of push and pop would use replace function of bimap.
One step in the A* pathfinding algorithm requires searching the list of open nodes for the node you're currently interacting with, and adding that node to the list if it isn't already there, or updating its value and parent, if it's present but with a higher weight than the current version of the node.
These behaviors aren't supported in the STL priority_queue structure. How should I implement that step?
Updates since this question is getting a lot of views:
std::priority_queue may look like a good choice for this, but it isn't.
Implementing A* yourself is an enormous confidence-booster, but after you've done it, you should try to switch to using the one provided by boost. I was nervous about installing it when I asked this question, but installation is very easy and won't produce any complications; and A* isn't the only useful functionality that boost provides. (In particular, if you don't use their string-processing functionality, you'll end up writing your own copy of it; I speak from personal experience...)
You can use a plain vector or array to store the elements and then use std::make_heap, std::push_heap, std::pop_heap, std::sort_heap, std::is_heap and std::is_heap_until to manage it.
This allows you to break containment and implement custom operations on a priority queue, without having to implement the standard operations yourself.
If you are limited to STL you could use STL Set and constantly erasing and re-inserting the elements (with new priority).
Set< pair<int,int> > s; // < priority,value >
s.insert( make_pair(0,5) );
// Decrease Key operation //
s.erase( s.find( make_pair(0,5) ) );
s.insert( make_pair(1,5) );
Time complexity is still O(log N) but it will probably take more time for large sets.
STL priority_queue does not suit for A* implementation. You need a heap structure that supports the increase operation to change the priority of already inserted items. Use Boost.Heap for an implementation of many classical heaps.
EDIT: Boost.Graph library has an implementation of A* search too.
Here is the solution I used for this if you really want to use std::priority_queue:
When you need to update a node that is already in the priority queue, just insert a new node having the same state and a new cost value and parent into the queue. The most recently updated copy of this node will come off the queue first and be added to your visited set. To deal with the older duplicates, check any node coming off the queue against your visited set before processing it. If it is in the visited set then the lowest-cost path through this node has already been seen, so just ignore it and process the next node.
There are three likely solutions to this:
Track the list of nodes currently open independently of the priority queue. Try creating a list of nodes in the same manner you do for closed nodes.
Create a map of nodes (by coordinate) to open-closed state.
Install the Boost library, which includes a templated implementation of A* (I think in <graph>).
I have implemented a Bellman-Ford algorithm to solve a problem (with a graph), but this solution was too slow, so I have replaced the Bellman-Ford's queue with a heap (std::set) , so the solution for the shortest path will be found faster. (somehow close do Dijkstra algorithm)
Now, I insert the node number in the heap, so the default std::set will sort the nodes using their number, not their cost. Everything is fine, and the algorithm gives the corect answers.
If I impelement a custom compare function for the std::set , so that the nodes will be sorted by their distance and not by their number the algorithm does no longer provide the shortest distance to the rest of the nodes.
This is my compare function:
struct cmp{
bool operator() (const int &a,const int &b) const{
return (d[Q][a] < d[Q][b] );
}
};
set <int,cmp> q;
So, being a BF algorithm, the algorithm runs until no improvement can be made. Can the compare function somehow "mess" the std::set, because this is the only reason I can see why adding this comparison function will give wrong answers...
I mean, why would it work if the nodes are in a completely random order but won't work if they are ordered by their cost...
As far as I recall the Bellman-Ford algorithm it updates the distance of the node. Thus, using the weight as the key for std::set<T> doesn't easily work: the search in the std::set<T> wouldn't find the respective value if you just changed the distance. What you would need to do pursue this direction is to remove the node to be updated, change the node's distance, and reinsert it afterwards. Please also note that objects in std::set<T> need to have a unique key: inserting a key which already exists will fail.
You said that you are using the std::set<int> as some sort of a priority queue. Did you have a look at std::priority_queue<T>? This is doing exactly this but it tends to be more efficient than using a std::set<T>. The problem with std::priority_queue<T> is that you can't change an objects priority: you have only access to the current top. A long time ago I had create a collection of priority queues (heaps) which included versions of the priority queues allowing changes to an object's priority (they were part of the initial libraries for Boost but they never made it through the review process). I don't know how you use your priority queue and thus I don't know whether this is reasonable direction to look at.
That said, I don't see why you would want to a std::set<T> for the Bellman-Ford algorithm anyway. My understanding is that the algorithm repeatedly goes through the graph and updates nodes with their new shortest distance. Did you have a look at Boost's implementation of the Bellman-Ford algorithm?