Given a unweighted and undirected tree with N nodes and N-1 edges I need to find minimum distance between source S and destination D.
Code :
vector<vector<int> >G(110);
bool check(int node,vector<int>path)
{
for(int i=0;i<path.size();++i)
{
if(path[i]==node)
return false;
}
return true;
}
int findMinpath(int source,int target,int totalnode,int totaledge)
{
vector<int>path;
path.push_back(source);
queue<vector<int> >q;
q.push(path);
while(!q.empty())
{
path=q.front();
q.pop();
int lastNode=path[path.size()-1];
if(lastNode==target)
{
return path.size()-1;
}
for(int i=0;i<G[lastNode].size();++i){
if(check(G[lastNode][i],path)){
vector<int>new_path(path.begin(),path.end());
new_path.push_back(G[lastNode][i]);
q.push(new_path);
}}}
return 1;
}
And then in main :
int N,S,E;
cin>>N>>S>>E;
for(int i=1;i<=N-1;++i)
{
int u,v;
cin>>u>>v;
G[u].push_back(v);
G[v].push_back(u);
}
cout<<findpaths(S,E,N,N-1)<<"\n";
Can it be further optimised as I need just minimum distance between S and E
You seem to be pushing vectors to your queue, each vector containing the actual path so far. But you can get away with only pushing nodes, since you only use the last node in those vectors anyway, and instead store the distance to each node from the source.
This will be much faster because you won't be copying vectors at each step.
Keep track of the distances in an array and also use them to make sure you don't visit a node multiple times.
Untested, but should get the point across:
int distance[110 + 1]; // d[i] = distance from source to i, initialize with a large number
int findMinpath(int source,int target,int totalnode,int totaledge)
{
for (int i = 0; i <= totalnode; ++i)
{
distance[i] = 2000000000;
}
queue<int> q;
q.push(source);
distance[source] = 0;
while(!q.empty())
{
node=q.front();
q.pop();
if(node==target)
{
return distance[node];
}
for(int i=0;i<G[node].size();++i){
if(distance[node] + 1 < distance[ G[node][i] ]){
distance[ G[node][i] ] = distance[node] + 1
q.push(G[node][i]);
}}}
return 1;
}
In the input specification N the number of nodes and M the number of edges are given . So the first simple check is that M should be equal to N-1 otherwise it simply can't be a tree.
What I did next was just a DFS in which I see that whether during the DFS we come across a visited a node again ( different from the parent node, by parent node I mean the node which has called the dfs of the next node adjacent to it ) then it means that we have a cycle and it isn't a tree . But apparently my solution keeps on getting a wrong answer . I am posting the code but only the snippets that are important . I am storing the graph as a adjacency list and I am posting the function isTree() which tests whether it is a tree or not ? What is the correct logic ?
#include <iostream>
#include <list>
using namespace std;
// Graph class represents a directed graph using adjacency list representation
class Graph
{
int V; // No. of vertices
list<int> *adj; // Pointer to an array containing adjacency lists
bool isTreeUtil(int v, bool visited[],int parent);
public:
Graph(int V); // Constructor
void addEdge(int v, int w); // function to add an edge to graph
bool isTree(); // Tells whether the given graph is a tree or not
void printGraph();
};
Graph::Graph(int V)
{
this->V = V;
adj = new list<int>[V+1];
}
void Graph::addEdge(int v, int w)
{
adj[v].push_back(w); // Add w to v’s list.
adj[w].push_back(v);
}
bool Graph::isTreeUtil(int v, bool visited[],int parent)
{
//int s_v = v;
visited[v] = true;
list<int>::iterator i;
for(i = adj[v].begin(); i != adj[v].end(); ++i) {
if (!visited[*i])
isTreeUtil(*i,visited,v);
else {
if (*i != parent && visited[*i])
return false;
}
}
return true;
}
bool Graph::isTree() {
bool *visited = new bool[V+1];
for(int i = 1; i < V+1; i++)
visited[i] = false;
visited[1] = true; // marking the first node as visited
for(int i = 1; i < V+1; i++)
visited[i] = false;
int parent = -1; // initially it has no parent
//list<int> :: iterator i;
//for (i = adj[v].begin(); i != adj[v].end(); ++i)
return isTreeUtil(1, visited, parent);
}
void Graph::printGraph() {
for (int i = 1;i <= this->V; i++) {
cout << i << "->";
list<int>::iterator j;
for (j = adj[i].begin(); j != adj[i].end(); ++j) {
cout << *j << "->";
}
cout << "\n";
}
}
int main() {
int N, M;
cin >> N >> M;
Graph G(N);
int v, w;
int m = 0;
while (m < M) {
cin >> v >> w;
G.addEdge(v,w);
m++;
}
if (M != N-1) {
cout << "NO\n";
else if (G.isTree())
cout << "YES\n";
else
cout << "NO\n";
}
I took your code, compiled, and ran it on my machine. When implementing a graph, there are important specs to consider. When you choose to obey a spec, it is generally good practice to enforce that spec in your code.
It is already clear that the graph has 2-way edges, though it does not hurt to specifically mention this.
Allow Duplicate Edges?
Your program allows me to make edge (1,2) and then another edge (1,2) and count it as 2 edges. This makes your conditional M != N-1 an insufficient check. Either disallow duplicate edges or account for them in your algorithm (currently, a duplicate edge will cause your algorithm to return incorrectly).
Self Edges?
Does your graph allow a vertex to have an edge to itself? If so, should the self-path invalidate the tree (perhaps a self-loop is legal because in a tree, every node can access itself)? Currently, self edges also break your algorithm.
To help you, here is my revised implementation of addEdge() that disallows duplicate edges and disallows self-loops. As a bonus it also checks for array bounds ;)
Please note that the additional include, and the change in function signature (it now returns a bool).
#include <algorithm>
bool Graph::addEdge(int v, int w)
{
// sanity check to keep us from seg faulting
if (v < 1 || v > this->V || w < 1 || w > this->V) {
return false;
}
// no self-edges
if (w == v) {
return false;
}
// no duplicate edges allowed either
std::list<int>::iterator findV = std::find(adj[v].begin(), adj[v].end(), w);
std::list<int>::iterator findW = std::find(adj[w].begin(), adj[w].end(), v);
if (findV != adj[v].end() || findW != adj[w].end()) {
return false;
}
adj[v].push_back(w); // Add w to v’s list.
adj[w].push_back(v);
return true;
}
I hope this helps. If this is an assignment, you should review the write-up. They must have specified these cases if your implementation was auto-graded. As #congusbongus mentioned, your algorithm also fails in the case of a disconnected node.
Please note that you also have to revise the main() method in order for my implementation to work. Change this part of the function:
while (m < M) {
cout << "Create Edge from x to y" << endl;
cin >> v >> w;
if (!G.addEdge(v,w)) {
cout << ">>Invalid edge not added" << endl;
} else {
cout << ">>Successfully added edge" << endl;
m++;
}
}
it runs for all the simple test cases I drew on paper but when submitting it fails !
Sounds like some auto-marking system for homework right? If you had access to the exact test cases, then the problem would be obvious. In this case it's probably not available, so we can only speculate.
In my experience, most failures of this kind are due to missed boundary cases. You say you check for number of edges = number of nodes - 1, but have you also considered the following?
All nodes connected
No more than one edge per pair of nodes
That is, is your program prepared to return "NO" for this?
_
/ \
o o---o
Nodes: 3, edges: 2
We want to find the farthest vertex to the i-th vertex,
farthest vertex to the current vertex of graph, gives the maximum Path to us.
Please help me to get this right:
vector<int> v[100];
bool mark[100];
int v1;
inline int max_path(int k)
{
int result = -1;
mark[k] = true;
for(int i=0; i<v[k].size(); i++)
if(!mark[v[k][i]])
{
int x = max_path(v[k][i]);
if(x > result)
{
result = x;
v1 = v[k][i];
}
}
return result+1;
}
v1 must be the farthest vertex to the current vertex (k), and result must be the length of the path.
You can use int result[n] and then print the max var of that...
We have a problem here, we're trying to find all the shortest paths in graph from one node to another. We have already implemented dijkstra but we really dont know how to find them all.
Do we have to use BFS?
#include <vector>
#include <iostream>
#include <queue>
using namespace std;
typedef pair <int, int> dist_node;
typedef pair <int, int> edge;
const int MAXN = 10000;
const int INF = 1 << 30;
vector <edge> g[MAXN];
int d[MAXN];
int p[MAXN];
int dijkstra(int s, int n,int t){
for (int i = 0; i <= n; ++i){
d[i] = INF; p[i] = -1;
}
priority_queue < dist_node, vector <dist_node>,greater<dist_node> > q;
d[s] = 0;
q.push(dist_node(0, s));
while (!q.empty()){
int dist = q.top().first;
int cur = q.top().second;
q.pop();
if (dist > d[cur]) continue;
for (int i = 0; i < g[cur].size(); ++i){
int next = g[cur][i].first;
int w_extra = g[cur][i].second;
if (d[cur] + w_extra < d[next]){
d[next] = d[cur] + w_extra;
p[next] = cur;
q.push(dist_node(d[next], next));
}
}
}
return d[t];
}
vector <int> findpath (int t){
vector <int> path;
int cur=t;
while(cur != -1){
path.push_back(cur);
cur = p[cur];
}
reverse(path.begin(), path.end());
return path;
}
This is our code, we believe we have to modify it but we really don't know where.
Currently, you are only saving/retrieving one of the shortest paths that you happen to find. Consider this example:
4 nodes
0 -> 1
0 -> 2
1 -> 3
2 -> 3
It becomes clear that you cannot have a single p[] value for each position, as in fact the 4th node (3) has 2 previous valid nodes: 1 and 2.
You could thus replace it with a vector<int> p[MAXN]; and work as follows:
if (d[cur] + w_extra < d[next]){
d[next] = d[cur] + w_extra;
p[next].clear();
p[next].push_back(cur);
q.push(dist_node(d[next], next));
}
else if(d[cur] + w_extra == d[next]){
p[next].push_back(cur); // a new shortest way of hitting this same node
}
You will also need to update your findpath() function as it will need to deal with "branches" resulting in several multiple paths, possibly an exponentially huge amount of paths depending on the graph. If you just need to print the paths, you could do something like this:
int answer[MAXN];
void findpath (int t, int depth){
if(t == -1){ // we reached the initial node of one shortest path
for(int i = depth-1; i >= 0; --i){
printf("%d ", answer[i]);
}
printf("%d\n", last_node); // the target end node of the search
return;
}
for(int i = p[t].size()-1; i >= 0; --i){
answer[depth] = p[t][i];
findpath(p[t][i], depth+1);
}
}
Note you'll need to do p[s].push_back(-1) at the beginning of your dijkstra, besides clearing this vector array between cases.
For example suppose there are 3 nodes A,B,C and A links to B and C, B links to A and C, and C links to B and A. In visual form its like this
C <- A -> B //A links to B & C
A <- B -> C //B links to A & C
B <- C -> A //C links to B & A
Assume the A,B,C are held in an array like so [A,B,C] with index starting at 0. How can I efficiently sort the array [A,B,C] according to the value held by each node.
For example if A holds 4, B holds -2 and C holds -1, then sortGraph([A,B,C]) should return [B,C,A]. Hope its clear. Would it be possible if I can somehow utilize std::sort?
EDIT: Not basic sort algorithm. Let me clarify a bit more. Assume I have a list of Nodes [n0,n1...nm]. Each ni has a left and right neighbor index. For example, n1 left neight is n0 and its right neighbor is n2. I use index to represent the neighbor. If n1 is at index 1, then its left neighbor is at index 0 and its right neighbor is at index 2. If I sort the array, then I need to update the neighbor index as well. I don't want to really implement my own sorting algorithm, any advice on how to proceed?
If I understand the edited question correctly your graph is a circular linked list: each node points to the previous and next nodes, and the "last" node points to the "first" node as its next node.
There's nothing particularly special you need to do the sort that you want. Here are the basic steps I'd use.
Put all the nodes into an array.
Sort the array using any sorting algorithm (e.g. qsort).
Loop through the result and reset the prev/next pointers for each node, taking into account the special cases for the first and last node.
Here is a C++ implementation, hope is useful (it includes several algorithms like dijkstra, kruskal, for sorting it uses depth first search, etc...)
Graph.h
#ifndef __GRAPH_H
#define __GRAPH_H
#include <vector>
#include <stack>
#include <set>
typedef struct __edge_t
{
int v0, v1, w;
__edge_t():v0(-1),v1(-1),w(-1){}
__edge_t(int from, int to, int weight):v0(from),v1(to),w(weight){}
} edge_t;
class Graph
{
public:
Graph(void); // construct a graph with no vertex (and thus no edge)
Graph(int n); // construct a graph with n-vertex, but no edge
Graph(const Graph &graph); // deep copy of a graph, avoid if not necessary
public:
// #destructor
virtual ~Graph(void);
public:
inline int getVertexCount(void) const { return this->numV; }
inline int getEdgeCount(void) const { return this->numE; }
public:
// add an edge
// #param: from [in] - starting point of the edge
// #param: to [in] - finishing point of the edge
// #param: weight[in] - edge weight, only allow positive values
void addEdge(int from, int to, int weight=1);
// get all edges
// #param: edgeList[out] - an array with sufficient size to store the edges
void getAllEdges(edge_t edgeList[]);
public:
// topological sort
// #param: vertexList[out] - vertex order
void sort(int vertexList[]);
// dijkstra's shortest path algorithm
// #param: v[in] - starting vertex
// #param: path[out] - an array of <distance, prev> pair for each vertex
void dijkstra(int v, std::pair<int, int> path[]);
// kruskal's minimum spanning tree algorithm
// #param: graph[out] - the minimum spanning tree result
void kruskal(Graph &graph);
// floyd-warshall shortest distance algorithm
// #param: path[out] - a matrix of <distance, next> pair in C-style
void floydWarshall(std::pair<int, int> path[]);
private:
// resursive depth first search
void sort(int v, std::pair<int, int> timestamp[], std::stack<int> &order);
// find which set the vertex is in, used in kruskal
std::set<int>* findSet(int v, std::set<int> vertexSet[], int n);
// union two sets, used in kruskal
void setUnion(std::set<int>* s0, std::set<int>* s1);
// initialize this graph
void init(int n);
// initialize this graph by copying another
void init(const Graph &graph);
private:
int numV, numE; // number of vertices and edges
std::vector< std::pair<int, int> >* adjList; // adjacency list
};
#endif
Graph.cpp
#include "Graph.h"
#include <algorithm>
#include <map>
Graph::Graph()
:numV(0), numE(0), adjList(0)
{
}
Graph::Graph(int n)
:numV(0), numE(0), adjList(0)
{
this->init(n);
}
Graph::Graph(const Graph &graph)
:numV(0), numE(0), adjList(0)
{
this->init(graph);
}
Graph::~Graph()
{
delete[] this->adjList;
}
void Graph::init(int n)
{
if(this->adjList){
delete[] this->adjList;
}
this->numV = n;
this->numE = 0;
this->adjList = new std::vector< std::pair<int, int> >[n];
}
void Graph::init(const Graph &graph)
{
this->init(graph.numV);
for(int i = 0; i < numV; i++){
this->adjList[i] = graph.adjList[i];
}
}
void Graph::addEdge(int from, int to, int weight)
{
if(weight > 0){
this->adjList[from].push_back( std::make_pair(to, weight) );
this->numE++;
}
}
void Graph::getAllEdges(edge_t edgeList[])
{
int k = 0;
for(int i = 0; i < numV; i++){
for(int j = 0; j < this->adjList[i].size(); j++){
// add this edge to edgeList
edgeList[k++] = edge_t(i, this->adjList[i][j].first, this->adjList[i][j].second);
}
}
}
void Graph::sort(int vertexList[])
{
std::pair<int, int>* timestamp = new std::pair<int, int>[this->numV];
std::stack<int> order;
for(int i = 0; i < this->numV; i++){
timestamp[i].first = -1;
timestamp[i].second = -1;
}
for(int v = 0; v < this->numV; v++){
if(timestamp[v].first < 0){
this->sort(v, timestamp, order);
}
}
int i = 0;
while(!order.empty()){
vertexList[i++] = order.top();
order.pop();
}
delete[] timestamp;
return;
}
void Graph::sort(int v, std::pair<int, int> timestamp[], std::stack<int> &order)
{
// discover vertex v
timestamp[v].first = 1;
for(int i = 0; i < this->adjList[v].size(); i++){
int next = this->adjList[v][i].first;
if(timestamp[next].first < 0){
this->sort(next, timestamp, order);
}
}
// finish vertex v
timestamp[v].second = 1;
order.push(v);
return;
}
void Graph::dijkstra(int v, std::pair<int, int> path[])
{
int* q = new int[numV];
int numQ = numV;
for(int i = 0; i < this->numV; i++){
path[i].first = -1; // infinity distance
path[i].second = -1; // no path exists
q[i] = i;
}
// instant reachable to itself
path[v].first = 0;
path[v].second = -1;
while(numQ > 0){
int u = -1; // such node not exists
for(int i = 0; i < numV; i++){
if(q[i] >= 0
&& path[i].first >= 0
&& (u < 0 || path[i].first < path[u].first)){ //
u = i;
}
}
if(u == -1){
// all remaining nodes are unreachible
break;
}
// remove u from Q
q[u] = -1;
numQ--;
for(int i = 0; i < this->adjList[u].size(); i++){
std::pair<int, int>& edge = this->adjList[u][i];
int alt = path[u].first + edge.second;
if(path[edge.first].first < 0 || alt < path[ edge.first ].first){
path[ edge.first ].first = alt;
path[ edge.first ].second = u;
}
}
}
delete[] q;
return;
}
// compare two edges by their weight
bool edgeCmp(edge_t e0, edge_t e1)
{
return e0.w < e1.w;
}
std::set<int>* Graph::findSet(int v, std::set<int> vertexSet[], int n)
{
for(int i = 0; i < n; i++){
if(vertexSet[i].find(v) != vertexSet[i].end()){
return vertexSet+i;
}
}
return 0;
}
void Graph::setUnion(std::set<int>* s0, std::set<int>* s1)
{
if(s1->size() > s0->size()){
std::set<int>* temp = s0;
s0 = s1;
s1 = temp;
}
for(std::set<int>::iterator i = s1->begin(); i != s1->end(); i++){
s0->insert(*i);
}
s1->clear();
return;
}
void Graph::kruskal(Graph &graph)
{
std::vector<edge_t> edgeList;
edgeList.reserve(numE);
for(int i = 0; i < numV; i++){
for(int j = 0; j < this->adjList[i].size(); j++){
// add this edge to edgeList
edgeList.push_back( edge_t(i, this->adjList[i][j].first, this->adjList[i][j].second) );
}
}
// sort the list in ascending order
std::sort(edgeList.begin(), edgeList.end(), edgeCmp);
graph.init(numV);
// create disjoint set of the spanning tree constructed so far
std::set<int>* disjoint = new std::set<int>[this->numV];
for(int i = 0; i < numV; i++){
disjoint[i].insert(i);
}
for(int e = 0; e < edgeList.size(); e++){
// consider edgeList[e]
std::set<int>* s0 = this->findSet(edgeList[e].v0, disjoint, numV);
std::set<int>* s1 = this->findSet(edgeList[e].v1, disjoint, numV);
if(s0 == s1){
// adding this edge will make a cycle
continue;
}
// add this edge to MST
graph.addEdge(edgeList[e].v0, edgeList[e].v1, edgeList[e].w);
// union s0 & s1
this->setUnion(s0, s1);
}
delete[] disjoint;
return;
}
#define IDX(i,j) ((i)*numV+(j))
void Graph::floydWarshall(std::pair<int, int> path[])
{
// initialize
for(int i = 0; i < numV; i++){
for(int j = 0; j < numV; j++){
path[IDX(i,j)].first = -1;
path[IDX(i,j)].second = -1;
}
}
for(int i = 0; i < numV; i++){
for(int j = 0; j < this->adjList[i].size(); j++){
path[IDX(i,this->adjList[i][j].first)].first
= this->adjList[i][j].second;
path[IDX(i,this->adjList[i][j].first)].second
= this->adjList[i][j].first;
}
}
// dynamic programming
for(int k = 0; k < numV; k++){
for(int i = 0; i < numV; i++){
for(int j = 0; j < numV; j++){
if(path[IDX(i,k)].first == -1
|| path[IDX(k,j)].first == -1){
// no path exist from i-to-k or from k-to-j
continue;
}
if(path[IDX(i,j)].first == -1
|| path[IDX(i,j)].first > path[IDX(i,k)].first + path[IDX(k,j)].first){
// there is a shorter path from i-to-k, and from k-to-j
path[IDX(i,j)].first = path[IDX(i,k)].first + path[IDX(k,j)].first;
path[IDX(i,j)].second = k;
}
}
}
}
return;
}
If you are looking for sorting algorithms you should just ask google:
http://en.wikipedia.org/wiki/Sorting_algorithm
My personal favourite is the BogoSort coupled with parallel universe theory. The theory is that if you hook a machine up to the program that can destroy the universe, then if the list isn't sorted after one iteration it will destroy the universe. That way all the parallel universes except the one with the list sorted will be destroyed and you have a sorting algorithm with complexity O(1).
The best ....
Create a struct like this:
template<typename Container, typename Comparison = std::less<typename Container::value_type>>
struct SortHelper
{
Container const* container;
size_t org_index;
SortHelper( Container const* c, size_t index ):container(c), org_index(index) {}
bool operator<( SortHelper other ) const
{
return Comparison()( (*c)[org_index], (*other.c)[other.org_index] );
}
};
This lets you resort things however you want.
Now, make a std::vector<SortHelper<blah>>, sort it, and you now have a vector of instructions of where everything ends up going after you sort it.
Apply these instructions (there are a few ways). An easy way would be to reuse container pointer as a bool. Walk the sorted vector of helpers. Move the first entry to where it should go, moving what you found where it should go to where it should go, and repeat until you loop or the entire array is sorted. As you go, clear the container pointers in your helper struct, and check them to make sure you don't move an entry that has already been moved (this lets you detect loops, for example).
Once a loop has occurred, proceed down the vector looking for the next as-yet-not-in-right-place entry (with a non-null container pointer).