In my class I have an assignment directed as follows:
In this lab, you will implement a Maze Solver, using a variety of graph-search algorithms.
Implement a templated Graph data structure, implementing the following functionality:
Add Node
Add Adjacency (given node, and adjacent node)
Breadth-First Search
Depth-First Search
Dijkstra’s Shortest Path Algorithm
To evaluate this data structure, write a program that reads a data file (with the filename passed as a command line parameter) and populates the data structure.
A set of mazes will be provided in doc sharing.
Maze Data Format
The maze data files will be text files containing integers.
The first line gives the size of the maze, in ‘cells’, x first, then y, separated by a space.
The second line gives the coordinates of the ‘start’ of the maze (x, then y, separated by a space)
The third line gives the coordinates of the ‘end’ of the maze (x, then y, separated by a space
The remainder of the file is a grid of numbers the size of the maze, space separated, where each number represents an ‘open’ (0) or ‘closed’(1) cell. Your ‘player’ can move into open cells, but not closed cells.
For various provided mazes, evaluate the execution time of each algorithm and the final path length (number of nodes opened to find the path). Record this data, by dataset size (total number of cells in the maze).
First, I don't even know how to implement a graph in the first place. All the reference that I can find just tells me what a graph is but not how to even start coding it. Do I create a class or struct like in a linked list or tree? I have no idea on what I am supposed to do.
Here is what I have so far:
#include <list>
#include <map>
#include <queue>
template <typename T>
class Graph
{
T V; //vertices
list<T> *adj; //edges;
public:
Graph(T V); //constructor
void addEdge(T v, T w); //function to add an edge to the graph
void BFS(T s); //prints the bfs traversal
};
Graph(T V)
{
this->V = V;
adj = new list<T>[V];
}
void Graph::addEdge(T v, T w)
{
adj[v].push_back(w); //Add w to v's list
}
void Graph::BFS(T s)
{
//Mark all the vertices as not visited
bool *visited = new bool[V];
for (int i - 0; i<V; i++)
visited[i] = false;
// create a queue for BFS
list<int>queue;
//Mark the current node as visited and enque it
visited[s] = true;
queue.push_back(s);
//i will be used to get all adjacent vertices of a vertex
list<T>::iterator i;
while (!queue.empty())
{
//deque a vertex from queue and print it
s = queue.front();
cout << s << " ";
queue.pop_front();
for (i = adj[s].begin(); i != adj[s].end(); i++)
{
if (!visited[*i])
{
visited[*i] = true;
queue.push_back();
}
}
}
}
Please excuse the formatting as I never used this site and I dont know how to properly place a block of code
Related
I know there's so many threads about this topic, but none of the ones I have found had helped me.
I have to find all the Hamiltonian cycles on a undirected graph using BFS. I have the code that search for a cycle (not hamiltonian), now I need to modify it and here's my problem. I'm not sure how to do this in a proper manner without thinking recursiverly.
My thoughts are that in order to find all Hamiltonian cycles using BFS I need:
Keep a track of one possible cycle (path).
Keep a count of the numbers of visited nodes. If I arrive to a "n" node that has the source as parent, I will need to check if all nodes are already visited.
So, in order to have a Hamiltonian Cycle, I must visit all nodes only once and finish when I arrive to a node that is inside of visited ones and that has "source" as adjacent.
Here's my graph.
https://i.stack.imgur.com/siLDn.png
And here's my code
#include <bits/stdc++.h>
using namespace std;
void addEdge(vector<int> adj[], int u, int v)
{
adj[u].push_back(v);
adj[v].push_back(u);
}
// return true if there's a cycle on the graph
bool thereIsCycle(vector<int> adj[], int s, int V)
{
// Mark all the vertices as not visited
vector<bool> visited(V, false);
// Set parent vertex for every vertex as -1.
vector<int> parent(V, -1);
// Create a queue for BFS
queue<int> q;
// Mark the current node as
// visited and enqueue it
visited[s] = true;
q.push(s);
while (!q.empty()) {
// Dequeue a vertex from queue and print it
int u = q.front();
q.pop();
// Get all adjacent vertices of the dequeued
// vertex u. If a adjacent has not been visited,
// then mark it visited and enqueue it. We also
// mark parent so that parent is not considered
// for cycle.
for (auto v : adj[u]) {
if (!visited[v]) {
visited[v] = true;
q.push(v);
parent[v] = u;
}
else if (parent[u] != v){
return true;
}
}
}
return false;
}
int main()
{
int V = 4;
vector<int> adj[V];
addEdge(adj, 0, 1);
addEdge(adj, 1, 2);
addEdge(adj, 2, 0);
addEdge(adj, 2, 3);
// check if there is a cycle from node 0
if (thereIsCycle(adj, 0, V)){
cout << "Yes";
}else{
cout << "No";
}
return 0;
}
Any suggests? Thank you all.
It looks like your code is currently looking for simple (non-Hamiltonian) cycles in the graph. If we add to the condition if (parent[u] != v){ return true; } checking that all vertices have been visited (all elements of the visited must be true), then it looks like the code will work correctly.
addEdge is not doing what you think it is.
Adj is intended to be the adjacency matrix of the graph. As implied by matrix this needs to be two dimensional.
2 for (auto v : adj[u]) makes no sense. adj[u] is an int, so it is meaningless to 'iterate' over it.
My suggestion: Take a step back and get the fundamentals right before tackling such an advanced problem. Create an actual graph class based on a correctly implemented adjacency matrix. Test you class with something simple, say listing all reachable nodes using BFS. Once that is working you can begin to move onto bigger challenges.
I have a tree of n nodes (labeled 0 to n). I used two vectors to hold the edge information.
typedef std::vector<std::vector<int>> graph;
The input is n-1 edges in the form:
0 1
1 2
2 3
and so on
I'm told node 0 is always the root node.
I scan the edges using the following:
for (int i = 0; i < n-1; i++) {
scanf("%d %d", &a, &b);
g[a].push_back(b);
g[b].push_back(a); // the second approach doesn't use this line
}
This is my simple dfs:
void dfs(graph &g, int v) {
std::vector<int> visited; // I don't use a visited array for the second approach
for (int i = 0; i < g.size(); i++) {
visited.push_back(0);
}
std::stack<int> s;
std::set<int> t;
s.push(v);
while (!s.empty()) {
int i = s.top(); s.pop();
// do stuff
for (int i = 0; i < g[v].size(); i++) {
if (!visited[i]) {
visited[i] = true;
s.push(g[v][i]);
}
}
}
}
For example say we have 4 nodes and the following edges:
0 1
0 2
3 2
2 4
Say that I'm interested in the sub tree starting at 2. The above approach won't work because I'm inserting undirected edges 0 2 and 2 0. So when I start my dfs at 2 I add node 0 to my stack which is wrong.
I tried another approach of only inserting the edges given only but that also didn't work because in the example I would've inserted 3 2 which is an edge from 3 to node 2 and so when I start my dfs at node 2 I won't be able to reach node 3.
I feel like the problem is simple and I'm missing some big idea!
Since your graph is a rooted tree, you can do the following preprocessing.
Start a DFS from root (vertex #0);
For each vertex u, store its parent v. It means that if you travel alongside shortest path from root to u, the second-to-last vertex on this path will be v. Notice that in any tree there is exactly one shortest path from one vertex to another. Let's say that you have an array parent such that parent[u] = v according to above definition, and parent[0] = -1.
You can compute parent array by noticing, that if you do s.push(g[v][i]), then v is the parent of i (otherwise you would have visited i first);
Since parent[v] is the previous vertex on shortest path from global root (vertex 0), it is also the previous vertex on shortest path from any vertex x, which contains v in its subtree.
Now when you want to DFS over subtree of vertex u, you do DFS as you do it now, but do not visit the parent of any vertex. Say, if you want to do s.push(v), while parent[u] = v, do not do it. This way you will never leave the subtree of u.
Actually, knowing parent, you can get rid of your visited array. When you "do stuff" with vertex v, the only neighbour of v that is already visited is parent[v]. This property does not depend on the initial vertex, whose subtree you want to traverse. The DFS code would look like this (assuming you've done preprocessing to obtain parent:
void dfs(graph &g, vector<int> &parent, int v) {
std::stack<int> s;
s.push(v);
while (!s.empty()) {
int v = s.top(); s.pop(); // By the way, you have mistake here: int i = s.top().
// do stuff
for (int i = 0; i < g[v].size(); i++) {
if (parent[v] != g[v][i]) {
s.push(g[v][i]);
}
}
}
}
PS This approach is somehow similar to your second approach: it only treats edges that go from root to subtree. But it does not have the flaw, such as in your example with "3 2" being the wrong direction, because you infer direction algorithmically by doing DFS from root.
Link to runnable program and program requirements/specs:
https://github.com/edgr-sanchez/CSCE2110-Graph
I've thus far implemented 95% of the program. Everything runs properly and has been tested using the provided test file.
The only thing that I'm having trouble implementing is Kruskal's Algorithm, and this is because I'm not quite sure how I need to use my existing data structure to pass it through Kruskal's.
To clarify a few things: Running Kruskal's Algorithm in this program is not supposed to make changes to the existing data, it should only calculate the minimum spanning tree and print it out.
Running the kruskal command on my program should output the minimum spanning tree in adjacency list format including the street name (S##) and the distance, like this:
NH NK(S02,11) NP(S03,13)
NK NH(S02,11) NL(S01,24)
NL NK(S01,24)
NM NW(S05,15)
NP NH(S03,13) NW(S07,12)
NW NM(S05,15) NP(S07,12)
The location where I need to implement this is in /src/SanE_10_P3_AdjacencyMatrix.cpp line 208.
Anyways, I'm providing my code and all this information to help you understand my code. I do not expect it to be written for me. I'd love to simply have some guidance on how to implement this using my existing struct:
struct {
bool exists = false;
std::string name = "";
int distance = empty;
} node[MAXNODES][MAXNODES];
This is the current output as well as the remaining expected output:
http://i.imgur.com/fMXTaGn.png
Thanks in advance!
At first I want to make a note: in fact, your node array describes edges, not nodes. Nodes here are indexes. Anyway, I leave the name as is. I presume that your graph is undirected. Here is how Kruskal algorithm can be implemented with your structure.
Define the function:
std::vector<std::pair<int, int>> kruskal()
{
std::vector<std::pair<int, int>> mst; //our result
At the very beginning we split all the vertices to separate trees. Each tree is identified by an index. We create a lookup table treesByVertex for finding an index of a tree by vertex.
std::map<int, std::set<int>> trees;
std::map<int, int> treeByVertex;
for (int i = 0; i < MAXNODES; ++i)
{
std::set<int> tree; // a tree containing a single vertex
tree.emplace(i);
trees.emplace(i, tree); //at startup, the index of a tree is equaled to the index of a vertex
treeByVertex.emplace(i, i);
}
Then we create a helper structure edges that will contain a list of edges with ascending distances:
std::multimap<int, std::pair<int, int>> edges;
for (int i = 1; i < MAXNODES; ++i)
for (int j = 0; j < i; ++j)
if (node[i][j].exists)
edges.emplace(node[i][j].distance, std::make_pair(i, j));
Iterate over all the edges in ascending order and test if it connects two different trees. If it's true, we add this edge to mst and merge these two trees:
for (const auto& e : edges)
{
int v1 = e.second.first;
int v2 = e.second.second;
if (treeByVertex[v1] != treeByVertex[v2]) //use our lookup table to find out if two vertexes belong to different trees
{
mst.emplace_back(v1, v2); //the edge is in mst
trees[v1].insert(trees[v2].begin(), trees[v2].end()); //merge trees
for (int v : trees[v2]) //modify lookup table after merging
treeByVertex[v] = treeByVertex[v1];
}
}
return mst;
}
In fact, you even don't need trees container here at all.
I'm having some trouble getting this implementation of Prim's to track the total weight of the shortest path it finds. The path seems to be correct but I can't figure out where to sum the weights as they are added to the array that stores the paths (since it was written only to store paths used).
I've tried summing pCrawl->weight as each vertex is added to the MST but that seems to be the sum of all the weights on the graph. Same with the values key[].
My question is what can be summed each time a path is added to the MST to reflect the total weight of the MST when all shortest paths have been added.
Here's the code I'm using: http://pastebin.com/TFLGCE0L
The Adjacency List I made: http://pastebin.com/SvgGjEPj
And the map used to create it: Map
The Prim's function looks like this:
// The main function that constructs Minimum Spanning Tree (MST)
// using Prim's algorithm
void PrimMST(struct Graph* graph)
{
int V = graph->V;// Get the number of vertices in graph
int parent[V]; // Array to store constructed MST
int key[V]; // Key values used to pick minimum weight edge in cut
// minHeap represents set E
struct MinHeap* minHeap = createMinHeap(V);
// Initialize min heap with all vertices. Key value of
// all vertices (except 0th vertex) is initially infinite
for (int v = 1; v < V; ++v)
{
parent[v] = -1;
key[v] = INT_MAX;
minHeap->array[v] = newMinHeapNode(v, key[v]);
minHeap->pos[v] = v;
}
// Make key value of 0th vertex as 0 so that it
// is extracted first
key[0] = 0;
minHeap->array[0] = newMinHeapNode(0, key[0]);
minHeap->pos[0] = 0;
// Initially size of min heap is equal to V
minHeap->size = V;
// In the followin loop, min heap contains all nodes
// not yet added to MST.
while (!isEmpty(minHeap))
{
// Extract the vertex with minimum key value
struct MinHeapNode* minHeapNode = extractMin(minHeap);
int u = minHeapNode->v; // Store the extracted vertex number
// Traverse through all adjacent vertices of u (the extracted
// vertex) and update their key values
struct AdjListNode* pCrawl = graph->array[u].head;
while (pCrawl != NULL)
{
int v = pCrawl->dest;
// If v is not yet included in MST and weight of u-v is
// less than key value of v, then update key value and
// parent of v
if (isInMinHeap(minHeap, v) && pCrawl->weight < key[v])
{
key[v] = pCrawl->weight;
parent[v] = u;
decreaseKey(minHeap, v, key[v]);
}
pCrawl = pCrawl->next;
}
}
The structs used look like this:
// A structure to represent a node in adjacency list
struct AdjListNode
{
int dest;
int weight;
struct AdjListNode* next;
};
// A structure to represent an adjacency liat
struct AdjList
{
struct AdjListNode *head; // pointer to head node of list
};
// A structure to represent a graph. A graph is an array of adjacency lists.
// Size of array will be V (number of vertices in graph)
struct Graph
{
int V;
struct AdjList* array;
};
// Structure to represent a min heap node
struct MinHeapNode
{
int v;
int key;
};
// Structure to represent a min heap
struct MinHeap
{
int size; // Number of heap nodes present currently
int capacity; // Capacity of min heap
int *pos; // This is needed for decreaseKey()
struct MinHeapNode **array;
};
I feel like I'm in way over my head in this data structures course, hence trying to use code from the internet to solve this small part of the assignment without fulling understanding :/
Thanks,
Michael
You are doing the right thing. Sum of minimum weights (from Prim's) can be equal to sum of all the weights on the graph. Consider the case when there are 4 nodes in a graph and node 1 is at the center and is connected to nodes 2, 3 and 4 with weights of w. 2, 3 and 4 are not connected among themselves. In this case Prim's weight would come out to be 3*w which is same as total weight. I would suggest you to use few different cases, that would clarify what I'm saying.
Edit:
Here is the issue, you are not updating the sum properly.
This -
weightTotal += pCrawl->weight
should be -
weightTotal += pCrawl->weight - key[v]
The issue is I need to create a random undirected graph to test the benchmark of Dijkstra's algorithm using an array and heap to store vertices. AFAIK a heap implementation shall be faster than an array when running on sparse and average graphs, however when it comes to dense graphs, the heap should became less efficient than an array.
I tried to write code that will produce a graph based on the input - number of vertices and total number of edges (maximum number of edges in undirected graph is n(n-1)/2).
On the entrance I divide the total number of edges by the number of vertices so that I have a const number of edges coming out from every single vertex. The graph is represented by an adjacency list. Here is what I came up with:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <list>
#include <set>
#define MAX 1000
#define MIN 1
class Vertex
{
public:
int Number;
int Distance;
Vertex(void);
Vertex(int, int);
~Vertex(void);
};
Vertex::Vertex(void)
{
Number = 0;
Distance = 0;
}
Vertex::Vertex(int C, int D)
{
Number = C;
Distance = D;
}
Vertex::~Vertex(void)
{
}
int main()
{
int VertexNumber, EdgeNumber;
while(scanf("%d %d", &VertexNumber, &EdgeNumber) > 0)
{
int EdgesFromVertex = (EdgeNumber/VertexNumber);
std::list<Vertex>* Graph = new std::list<Vertex> [VertexNumber];
srand(time(NULL));
int Distance, Neighbour;
bool Exist, First;
std::set<std::pair<int, int>> Added;
for(int i = 0; i < VertexNumber; i++)
{
for(int j = 0; j < EdgesFromVertex; j++)
{
First = true;
Exist = true;
while(First || Exist)
{
Neighbour = rand() % (VertexNumber - 1) + 0;
if(!Added.count(std::pair<int, int>(i, Neighbour)))
{
Added.insert(std::pair<int, int>(i, Neighbour));
Exist = false;
}
First = false;
}
}
First = true;
std::set<std::pair<int, int>>::iterator next = Added.begin();
for(std::set<std::pair<int, int>>::iterator it = Added.begin(); it != Added.end();)
{
if(!First)
Added.erase(next);
Distance = rand() % MAX + MIN;
Graph[it->first].push_back(Vertex(it->second, Distance));
Graph[it->second].push_back(Vertex(it->first, Distance));
std::set<std::pair<int, int>>::iterator next = it;
First = false;
}
}
// Dijkstra's implementation
}
return 0;
}
I get an error:
set iterator not dereferencable" when trying to create graph from set data.
I know it has something to do with erasing set elements on the fly, however I need to erase them asap to diminish memory usage.
Maybe there's a better way to create some undirectioned graph? Mine is pretty raw, but that's the best I came up with. I was thinking about making a directed graph which is easier task, but it doesn't ensure that every two vertices will be connected.
I would be grateful for any tips and solutions!
Piotry had basically the same idea I did, but he left off a step.
Only read half the matrix, and ignore you diagonal for writing values to. If you always want a node to have an edge to itself, add a one at the diagonal. If you always do not want a node to have an edge to itself, leave it as a zero.
You can read the other half of your matrix for a second graph for testing your implementation.
Look at the description of std::set::erase :
Iterator validity
Iterators, pointers and references referring to elements removed by
the function are invalidated.
All other iterators, pointers and
references keep their validity.
In your code, if next is equal to it, and you erase element of std::set by next, you can't use it. In this case you must (at least) change it and only after this keep using of it.