I am trying to detect the cycle in a directed graph. Initially, I have assumed all nodes to be unvisited and have their value as -1 in vector<int>flag. Now we start from a source node and push into stack<int>s and make flag[source]=0 as it is present in stack. Now I will do the DFS traversal and push the nodes if(flag[node]==-1)& make flag[node]=0 in stack starting with that particular source that I pushed in first. if all the DFS directed links are visited I will pop the top element of the stack and mark it flag[s.top()]=1;
while pushing if we encounter a node with flag[nodes]==0, the cycle is detected and i do an increment in int final variable;`
my code works correctly but there is a little issue. for e.g for input with number of vertices and edges =3.
input edges:{1,3},{2,3},{3,2}
input format;
3 3
1 3
2 3
3 2
expected out: "Graph is cyclic"
if i take the only source as 2 then i get the correct answer, but if we have to check it considering each vertex as source so i use a for loop but now i get the wrong output Graph is not cyclic. will kindly request why my approach go wrong.
my code:
#include<iostream>
#include<vector>
#include<stack>
#include<map>
using namespace std;
int mx=1e5+5;
vector<bool>vist(mx);
vector<vector<int>>Graph(mx);
void dfs(int node,vector<int>&dfs_vec){
vist[node]=true;
dfs_vec.push_back(node);
for(int neigh: Graph[node]){
if(!vist[neigh]){
dfs(neigh,dfs_vec);
}
}
}
int main(){
int num_vertex;int num_edge;
cin>>num_vertex>>num_edge;
int u,v;
for(int i=0;i<num_edge;i++){
cin>>u>>v;
Graph[u].push_back(v);
}
int final=0;
for(int source=1;source<=num_vertex;source++){
vector<int>flag(num_vertex+1,-1);
stack<int>s;
s.push(source);
flag[source]=0;
while(!s.empty()){
int x=s.top();
vector<int>temp;
dfs(Graph[x][0],temp);
for(auto y:temp){
if(flag[y]==-1){
s.push(y);
flag[y]=0;
}
else if(flag[y]==0){
final++;
}
}
flag[s.top()]=1;
s.pop();
}
flag.clear();
while(!s.empty()){
s.pop();
}
}
if(final>0){
std::cout<<" Graph is cyclic";
}
else{
std::cout<<" Graph is not cyclic";
}
}
Related
I have a directed graph. Initially, all nodes are assumed to be unvisited and flag is -1 in vector<int>flag. Now we start from a source node & push into stack<int>s and make flag[source]=0 . Now I do DFS traversal & push nodes if(flag[node]==-1)& make flag[node]=0. if all the DFS directed links are visited I pop the element of the stack and mark it flag[s.top()]=1; while pushing if we encounter a node with flag[nodes]==0, the cycle is detected and i do an increment in int final variable;`
you can see in my code, I am storing DFS traversal in a temp vector, which I think is garbage, how can I directly pass these connected nodes directly to check the flag and detect the cycle. currently my code works but fails for larger input. kindly looking for help.
#include<iostream>
#include<vector>
#include<stack>
#include<map>
using namespace std;
int mx=1e5+5;
vector<bool>vist(mx);
vector<vector<int>>Graph(mx);
void dfs(int node,vector<int>&dfs_vec){
vist[node]=true;
dfs_vec.push_back(node);
for(int neigh: Graph[node]){
if(!vist[neigh]){
dfs(neigh,dfs_vec);
}
}
}
//my temp vector is in while loop of main.
int main(){
int num_vertex;int num_edge;
cin>>num_vertex>>num_edge;
int u,v;
for(int i=0;i<num_edge;i++){
cin>>u>>v;
Graph[u].push_back(v);
}
vector<int>flag(num_vertex+1,-1);
stack<int>s;
int source=1;
s.push(source);
flag[source]=0;
int final=0;
while(!s.empty()){
int x=s.top();
vector<int>temp;
dfs(Graph[x][0],temp);
for(auto y:temp){
if(flag[y]==-1){
s.push(y);
flag[y]=0;
}
else if(flag[y]==0){
final++;
}
}
flag[s.top()]=1;
s.pop();
vist.clear();
vist.resize(mx);
}
if(final>0){
std::cout<<"Graph is cyclic";
}
else{
std::cout<<"Graph is not cyclic";
}
}
It is important to minimize the parameters in the signature of a recursive function if you want to handle large datasets. Each call requires the parameters to be kept on the stack, a fairly limited resource.
To minimize the parameters, use a method on a class which stores just one copy of the parameter data as an attribute whenever possible. For DFS, everything except the index of the currently visited node can be moved out of the parameter list.
Here is a straight forward implementation of DFS which I have used successfully on graphs containing hundreds of thousands of vertices.
void cPathFinder::depthRecurse(
int v )
{
visitor(v);
// remember this node has been visited
myPath[v] = 1;
// look for new adjacent nodes
for (int w : adjacent(v))
if (!myPath[w])
{
// search from new node
depthRecurse(w, visitor);
}
}
FYI here is brief discussion of some of the issues to think about when designing a class to implement graph theory algorithms. https://github.com/JamesBremner/PathFinder2/wiki/cGraph-Class-Design
First I have created an un-directed graph of vertices, edges and weights.
In prims() function:
vertex[] array is initialized to INT_MAX for all indices i < n except 0 index. It will have smallest weights found till now.
bool isthere[] array to check either a vertex is visited or not.
list<int> s at first will have 5 (0-4 indices) values. After each for loop its value will pop.
vector<int> mset will keep the vertex chosen according to their smallest weight.
#include<bits/stdc++.h>
using namespace std;
void addEdge(vector<pair<int,int>>adj[],int u,int v,int wt){
adj[u].push_back(make_pair(v,wt));
adj[v].push_back(make_pair(u,wt));
}
void print(vector<pair<int,int>>adj[],int v){
for(int i=0;i<v;++i){
cout<<i<<"-->";
vector<pair<int,int>>::iterator it;
for(it=adj[i].begin();it!=adj[i].end();++it){
cout<<it->first<<"-"<<it->second<<" ";
}
cout<<"\n";
}
}
void prims(vector<pair<int,int>>adj[],int v){
int vertex[v];
bool isthere[v];
vertex[0]=0;
isthere[0]=true;
list<int>s;
s.push_back(0);
for(int i=1;i<v;++i){
vertex[i]=INT_MAX;
isthere[i]=false;
s.push_back(i);
}
vector<int>mset;
int i=0;
while(!s.empty()){
isthere[i]=true;
mset.push_back(i);
s.pop_back();
cout<<"i="<<i<<" ";
int lesser=INT_MAX;
vector<pair<int,int>>::iterator it;
for(it=adj[i].begin();it!=adj[i].end();++it){
cout<<"it-"<<it->first<<" "<<it->second<<"\n";
if(isthere[it->first]==false && vertex[it->first]>it->second){
if(lesser>it->second){
lesser=it->second;
i=it->first;
cout<<"i="<<i<<" ";
}
vertex[it->first]=it->second;
}
}
}
}
int main(){
int v=5;
vector<pair<int,int>>adj[v];
addEdge(adj,0,1,2);
addEdge(adj,0,2,8);
addEdge(adj,1,3,21);
addEdge(adj,4,1,6);
addEdge(adj,2,1,0);
addEdge(adj,2,4,5);
addEdge(adj,3,4,9);
print(adj,v);
prims(adj,v);
return 0;
}
Here's my adjacency list. It is an array of vector of pairs denoting vertex, weight.
0-->1-2 2-8
1-->0-2 3-21 4-6 2-0
2-->0-8 1-0 4-5
3-->1-21 4-9
4-->1-6 2-5 3-9
Here's the debug output and the error I got in the prims() function.
i=0 it-1 2
i=1 it-2 8
it-0 0
it- -874898181 134251312
Process returned -1073741819 (0xC0000005) execution time : 0.835 s
Press any key to continue.
for(it=adj[i].begin();it!=adj[i].end();++it){
// ...
i=it->first;
// ...
}
This code exhibits undefined behavior, as it compares an iterator into one container with iterator into a different one. it is initialized with, say, adj[0].begin(), then i changes inside the loop, and on the next iteration the iterator is compared with, say, adj[1].end()
I am implementing graph algorithm on Hackerrank.
Problem statement :
The Ruler of HackerLand believes that every citizen of the country should have access to a library. Unfortunately, HackerLand was hit by a tornado that destroyed all of its libraries and obstructed its roads! As you are the greatest programmer of HackerLand, the ruler wants your help to repair the roads and build some new libraries efficiently.
HackerLand has n cities numbered from 1 to n. The cities are connected by m bidirectional roads. A citizen has access to a library if:
Their city contains a library.
They can travel by road from their city to a city containing a library.
The following figure is a sample map of HackerLand where the dotted lines denote obstructed roads:
The cost of repairing any road is c_road dollars, and the cost to build a library in any city is c_lib dollars. If in the above example c_road=2 and c_lib=3 , we would build 5 roads at a cost of 5*2 and 2 libraries for a cost of 6 . We don't need to rebuild one of the roads in the cycle 1->2->3->1.
You are given q queries, where each query consists of a map of HackerLand and value of c_lib and c_road . For each query, find the minimum cost of making libraries accessible to all the citizens and print it on a new line.
My approach :
I make a graph with the given cities and roads, where each city denotes a node in the graph and each road denotes a edge. I used BFS algorithm to find connected components of the graph. Then make a library in each component, and build minimum number of roads so that components remains connected.
Answer :
Rerurn the minimum of two.
The cost of making a library in each component + repairing roads so that each component has minimum number of roads.
Making a library in each city.
In the above case cost of building a road is 2 dollars (c_road=2) and cost of making a library is 3 (c_lib=3).
Here, this graph has two components:
1,2,3,7 (road required is 3)
5,6,8 (road required is 2)
Cost of making a library in each component(2*3=6) + cost of buiding required road is (5*2=10) = 16
Cost of building a library in each node is (7*3=21)=21
So, 16 is the answer.
My Code :
Note : 1 based indexing of graph used in this program.
#include<bits/stdc++.h>
using namespace std;
class Graph{
int v; // number of vertices
vector<int>*adj;
public:
Graph(int V){
this->v=V+1;
this->adj=new vector<int>[this->v];
}
void addEdge(int u,int v,bool biDir=true){
adj[u].push_back(v);
if(biDir)
adj[v].push_back(u);
}
void bfs(int ar[]){
// create a array of boolean to keep track of visited nodes.
int numComponent=0,numEdge=0;
bool visited[this->v];
for(int i=1;i<this->v;i++)
visited[i]=false;
// for each node in graph
for(int i=1;i<this->v;i++){
if(!visited[i]){
numComponent++;
numEdge+=bfsUtill(i,visited);
}
}
ar[0]=numComponent;
ar[1]=numEdge;
}
int bfsUtill(int src, bool visited[]){
// make a queue and insert src into it
int numEdge=0;
queue<int>q;
q.push(src); // insert src into queue
// mark first node as visited
visited[src]=true;
while(!q.empty()){
int node=q.front();
// visit
cout<<node<<" ";
// remove this node from queue
q.pop();
// visit every node adjacent to node 'node'
// if that node not visited then visit and enque it.
for(int adjNode:adj[node]){
if(!visited[adjNode]){
numEdge++;
visited[adjNode]=true;
q.push(adjNode);
}
}
}
return numEdge;
}
};
// Complete the roadsAndLibraries function below.
long roadsAndLibraries(int n, int c_lib, int c_road, vector<vector<int>> cities) {
// if c_road is greater than c_lib then
if (c_road>c_lib){
return n*c_lib;
}
Graph g(n);
// make graph of given vertices
for(auto x:cities)
g.addEdge(x[0],x[1]);
// Array to store number of component and number of edges need to be repaired
int ar[2];
g.bfs(ar);
long long int libInEach=n*c_lib;
long long int roadAlso= ar[0]*c_lib+(ar[1]*c_road);
return min(libInEach,roadAlso);
}
// driver code
int main(){
int t,n,m,c_lib,c_road;
vector<vector<int>>cities;
vector<int>temp;
cin>>t;
while(t--){
cin>>n,m,c_lib,c_road;
int a,b;
for(int i=0;i<m;i++){
cin>>a>>b;
temp.push_back(a,b);
cities.push_back(temp);
temp.erase();
}
cout<<roadsAndLibraries(n,c_lib,c_road,cities);
}
return 0;
}
I am getting correct answer for some test cases and incorrect for some test cases.
I posted only required code, insted of whole program. Input is passed into this function roadsAndLibraries() .
I test helper function and those are working fine.
-bfs()
- bfsUtill()
Test cases :
2
3 3 2 1
1 2
3 1
2 3
6 6 2 5
1 3
3 4
2 4
1 2
2 3
5
Output for this test case :
4
12
I edited your code. This might work for your test cases on hackerrank. This is working fine on given test cases. In any component if totel number of vertices is n then minimum number of edges, that can represent the same connected component is n-1.
#include<bits/stdc++.h>
using namespace std;
class Graph{
int v; // number of vertices
vector<int>*adj;
public:
Graph(int V){
this->v=V+1;
this->adj=new vector<int>[this->v];
}
void addEdge(int u,int v,bool biDir=true){
adj[u].push_back(v);
if(biDir)
adj[v].push_back(u);
}
void bfs(int ar[]){
// create a array of boolean to keep track of visited nodes.
int numComponent=0,numEdge=0;
bool visited[this->v];
for(int i=1;i<this->v;i++)
visited[i]=false;
// for each node in graph
for(int i=1;i<this->v;i++){
if(!visited[i]){
numComponent++;
numEdge+=bfsUtill(i,visited);
}
}
ar[0]=numComponent;
ar[1]=numEdge;
}
int bfsUtill(int src, bool visited[]){
// make a queue and insert src into it
int numEdge=1;
queue<int>q;
q.push(src); // insert src into queue
// mark first node as visited
visited[src]=true;
while(!q.empty()){
int node=q.front();
// visit
cout<<node<<" ";
// remove this node from queue
q.pop();
// visit every node adjacent to node 'node'
// if that node not visited then visit and enque it.
for(int adjNode:adj[node]){
if(!visited[adjNode]){
numEdge++;
visited[adjNode]=true;
q.push(adjNode);
}
}
}
return numEdge-1;
}
};
// Complete the roadsAndLibraries function below.
long roadsAndLibraries(int n, int c_lib, int c_road, vector<vector<int>> cities) {
// if c_road is greater than c_lib then
if (c_road>c_lib){
return n*c_lib;
}
Graph g(n);
// make graph of given vertices
for(auto x:cities)
g.addEdge(x[0],x[1]);
// Array to store number of component and number of edges need to be repaired
int ar[2];
g.bfs(ar);
long long int libInEach=n*c_lib;
long long int roadAlso= ar[0]*c_lib+(ar[1]*c_road);
return min(libInEach,roadAlso);
}
// driver code
int main(){
int t,n,m,c_lib,c_road;
vector<vector<int>>cities;
vector<int>temp;
cin>>t;
while(t--){
cin>>n,m,c_lib,c_road;
int a,b;
for(int i=0;i<m;i++){
cin>>a>>b;
temp.push_back(a,b);
cities.push_back(temp);
temp.erase();
}
cout<<roadsAndLibraries(n,c_lib,c_road,cities);
}
return 0;
}
I am writing a program that will detect cycle in a directed graph and will print the nodes that built the cycle. I try use to use a recursive method using C++ by not understanding how to print these nodes after a cycle is detect. Here is my code:
#include <bits/stdc++.h>
using namespace std;
void addedge(list<int>,int ,int );
void cycle_check(list<int>*,int);
// Make a pair between vertex x and vertex y
void addedge(list<int> *ls,int x,int y){
ls[x].push_back(y);
return;
}
void check_cycle_util(list<int> *ls,bool *visit,int curr_node,int &temp){
visit[curr_node]=true;
list<int>::iterator it;
for(it=ls[curr_node].begin();it!=ls[curr_node].end();it++){
if(!visit[*it]){
check_cycle_util(ls,visit,*it,temp);
}
else{
if(temp==0){
temp=1;
cout<<"There is a cycle in the graph\n";
break;
}
}
}
}
//checking the cycles in a graph
void cycle_check(list<int>*ls,int num){
bool *visit=new bool[num];
int temp=0;
for(int i=0;i<num;i++)
visit[i]=false;
for(int i=0;i<num;i++){
if(!visit[i] && temp==0){
check_cycle_util(ls,visit,i,temp);
}
}
}
int main(){
int num;
cout<<"Enter the no. of vertices :";
cin>>num;
list<int> *ls=new list<int>[num];
addedge(ls,0,1);
addedge(ls,2,3);
addedge(ls,3,4);
addedge(ls,4,5);
addedge(ls,1,2);
addedge(ls,1,4);
addedge(ls,3,0);
cycle_check(ls,6);
return 0;
}
I think you could learn the Tarjan Shrink Point Algorithm, it's used to search the strongly connected components.
The main idea is using the same value to mark all the points of a strongly connected component. So the points have the same value are in the same cycle.
The main steps are these:
First, we define two arrays for points, one is the timestamp array, it means the sequence number in the DFS. The other is the low stamp array, it means the min value of the timestamp of the point through DFS, in other words, the value of one point is the min value among timestamp of the point itself and the low stamps of the linked points.
Use DFS to assign the low stamp array, and then all the points which have the same low stamp are in the same cycle.
P.s: Because my Engish is not good so that I can't explain the algorithm very clear. So I recommend you could see another article to learn about this algorithm.
This is an example for using the stack to save path:
the path is a vector defined as a global variable
visit[curr_node]=true;
path.push_back(curr_node);
/* other code */
if(temp==0){
temp=1;
cout<<"There is a cycle in the graph\n";
break;
for(auto i=path.size()-1;path[i]!=curr_node||i==path.size();--i){
cout<<path[i];
}
}
}
path.pop_back();
I have coded DFS as the way it is on my mind and didn't referred any Text book or Pseudo-code for ideas. I think I have some lines of codes that are making unnecessary calculations. Any ideas on reducing the complexity of my algorithm ?
vector<int>visited;
bool isFound(vector<int>vec,int value)
{
if(std::find(vec.begin(),vec.end(),value)==vec.end())
return false;
else
return true;
}
void dfs(int **graph,int numOfNodes,int node)
{
if(isFound(visited,node)==false)
visited.push_back(node);
vector<int>neighbours;
for(int i=0;i<numOfNodes;i++)
if(graph[node][i]==1)
neighbours.push_back(i);
for(int i=0;i<neighbours.size();i++)
if(isFound(visited,neighbours[i])==false)
dfs(graph,numOfNodes,neighbours[i]);
}
void depthFirstSearch(int **graph,int numOfNodes)
{
for(int i=0;i<numOfNodes;i++)
dfs(graph,numOfNodes,i);
}
PS: Could somebody please sent me a link teaching me how can to insert C++ code with good quality. I've tried syntax highlighting but it didn't work out.
Your DFS has O(n^2) time complexity, which is really bad (it should run in O(n + m)).
This line ruins your implementation, because searching in vector takes time proportional to its length:
if(std::find(vec.begin(),vec.end(),value)==vec.end())
To avoid this, you can remember what was visited in an array of boolean values.
Second problem with your DFS is that for bigger graph it will probably cause stack overflow, because worst case recursion depth is equal to number of vertices in graph. Remedy to this problem is also simple: use std::list<int> as your own stack.
So, code that does DFS should look more or less like this:
// n is number of vertices in graph
bool visited[n]; // in this array we save visited vertices
std::list<int> stack;
std::list<int> order;
for(int i = 0; i < n; i++){
if(!visited[i]){
stack.push_back(i);
while(!stack.empty()){
int top = stack.back();
stack.pop_back();
if(visited[top])
continue;
visited[top] = true;
order.push_back(top);
for(all neighbours of top)
if(!visited[neighbour])
stack.push_back(neighbour);
}
}
}