I was solving a problem to determine whether a graph contains a cycle. I solved it using the coloring method (in the visited array I will mark, 0 if it has never visited, 1 if it is visited, and 2 if the tour of vertex is done)
for this I wrote the code:
#include <bits/stdc++.h>
using namespace std;
vector<int> adj[20005];
int vis[20005];
int chk = 0;
void dfs(int u){
if(vis[u]==1) {
chk = 1;
return;
}
if(vis[u]==2) return;
vis[u] = 1;
for(auto v:adj[u]) dfs(v);
vis[u] = 2;
}
int main(){
int N, M; cin>>N>>M;
for(int i = 0; i<M; i++){
int p, q; cin>>p>>q;
adj[p].push_back(q);
}
for(int i = 1; i<=N; i++){
if(vis[i]==1) break;
if(!vis[i]) dfs(i);
}
cout<<(chk?"Yes\n":"No\n");
}
Now, I'm thinking, if there's a way to write the cycle which has been detected. I know most people will say DFS and backtracking and it's very intuitive. But want to know how do I implement it.
par[v] - parent node of v, pr - previously visited node:
void dfs(int u, int pr = -1){
if(vis[u]==1) {
vector<int> cycle();
int cur = pr;
while(cur != u) {
cycle.push_back(cur);
cur = par[cur]
}
cycle.push_back(u);
chk = 1;
return;
}
if(vis[u]==2) return;
vis[u] = 1;
par[u] = pr;
for(auto v:adj[u]) dfs(v, u);
vis[u] = 2;
}
Related
I have written the code to check if a cycle exists or not in a graph using breadth-first traversal.
If I declare the adjacency list as vectoradj[n]; then it's okay.
But the problem arises when I use vector<vector>adj(n)
Can someone tell me what is the error? and how can I use the latter option to run my code?
#include <bits/stdc++.h>
using namespace std;
bool checkForCycle(int s, int V, vector<vector<int>>adj, vector<int> &visited)
{
queue<pair<int, int>> q;
visited[s] = true;
q.push({s, -1});
while (!q.empty())
{
int node = q.front().first;
int par = q.front().second;
q.pop();
for (auto it : adj[node])
{
if (!visited[it])
{
visited[it] = true;
q.push({it, node});
}
else if (par != it)
return true;
}
}
return false;
}
bool isCycle(int V,vector<vector<int>>adj)
{
vector<int> vis(V - 1, 0);
for (int i = 1; i <= V; i++)
{
if (!vis[i])
{
if (checkForCycle(i, V, adj, vis))
return true;
}
}
}
int main() {
int n, m;
cout<<"Enter number of vertices :\n";
cin>>n;
cout<<"Enter number of edges :\n";
cin>>m;
vector<vector<int>>adj(n);
for(int i=0; i<m; i++) {
int u, v;
cin>>u>>v;
adj[u].push_back(v);
adj[v].push_back(u);
}
cout<<endl;
if(isCycle(n,adj))
cout<<"cycle present int the graph";
else
cout<<"No cycle present";
return 0;
}
okay so the error resolves if I use
vector<vector<int>>adj(n+1);
instead of
vector<vector<int>>adj(n);
I have the queue functions and I have to use them to count the number of graph components. These are my functions:
struct TQueue {
int value;
TQueue * next;
};
void QueueInit(TQueue * & a_head, TQueue * & a_tail) {
a_head = NULL;
a_tail = NULL;
};
bool IsQueueEmpty(TQueue * a_head) {
return !a_head;
};
void Enqueue(TQueue * & a_head, TQueue * & a_tail, int a_val) {
TQueue * l_hlp = new TQueue;
l_hlp->value = a_val;
l_hlp->next = NULL;
if (a_tail) a_tail->next = l_hlp;
if (!a_head) a_head = l_hlp;
a_tail = l_hlp;
}
int Dequeue(TQueue * & a_head, TQueue * & a_tail) {
int l_val = a_head->value;
TQueue * l_hlp = a_head;
a_head = a_head->next;
if (!a_head) a_tail = NULL;
delete l_hlp;
return l_val;
};
void EmptyQueue(TQueue * & a_head, TQueue * & a_tail) {
TQueue * l_hlp;
while (a_head) {
l_hlp = a_head;
a_head = a_head->next;
delete l_hlp;
}
a_tail = NULL;
};
And this is my main() function and some variables:
// constant - number of vertexes
const int n = 9;
// queue declaration
TQueue *phead, *ptail;
QueueInit(phead, ptail);
// array of distanc
int dist[n];
// distanc array initialization
for (int i = 0; i < n; i++) dist[i] = -1;
// current distance
int d = 0;
// processingvertex
int v;
// number of components
int c = 0;
I prefer to use stack and DFS but it's a school projec so I must to use queue and BFS algorithm.
The approach is same as you would do in a dfs based approach. Here is a general bfs implementation using queue which you can modify easily for your purpose(i.e.using a custom queue)
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
void bfs(int src, vector<bool>& vis, vector<vector<int>>& adj) {
queue<int> q;
q.push(src);
vis[src] = true;
while(!q.empty()) {
int u = q.front(); q.pop();
vis[u] = true;
for(int v : adj[u]) {
if(!vis[v]) q.push(v);
}
}
}
int main() {
int n, m;
cin >> n >> m;
vector<vector<int>> adj(n);
for(int i = 0; i < m; i++) {
int u, v;
cin >> u >> v;
adj[u].push_back(v);
adj[v].push_back(u);
}
int count = 0;
vector<bool> vis(n);
for(int i = 0; i < n; i++) {
if(!vis[i]) {
bfs(i, vis, adj);
count++;
}
}
cout << count << '\n';
}
Variables reference
n : number of nodes in graph
m : number of edges in graph
adj : adjacency list representation of graph
vis : array to store if node is visited or not
count : number of connected components in graph
Example Test Case
Input:
6 3
1 5
0 2
2 4
Output:
3
You can refer to this post on mathematics stack exchange for understanding the algorithm: Finding connected components in a graph using BFS
This is my attempt to code compute components and assign vertices to components:
for (int i = 0; i <= n - 1; i++) visited[i] = false;
c = 0;
while (1) {
c++;
all = true;
for (int i = 0; i < n; i++)
if (!visited[i]) {
all = false;
visited[i] = c;
fronta::Enqueue(phead, ptail, i);
break;
}
if (all) {
c--;
break;
}
fronta::Enqueue(phead, ptail, 0);
visited[0] = true;
while (!fronta::IsQueueEmpty(phead)) {
v = fronta::Dequeue(phead, ptail);
//cout << "processing vertex: " << v << endl;
for (int j = 0; j < n; j++) {
if (gr3[v][j] && !visited[j]) {
fronta::Enqueue(phead, ptail, j);
visited[j] = true;
}
}
}
}
But it doesn't work very well...
I have a DFS function which collects entry and leave times of vertices. Unfortunately, I am unable to receive a proper value for leave time, because it is not connected with the value from recursive call.
void DFS_visit(int i, vector<int> Adj[], int visited[], int p[], int entry[], int leave[], int t)
{
visited[i] = 1;
entry[i] = t;
cout << i << " ";
for (auto u : Adj[i])
{
if (!visited[u])
{
p[u] = i;
DFS_visit(u, Adj, visited, p, entry, leave, t++);
}
}
leave[i] = t++;
}
It is obviously an auxiliary function, I also have a "main" DFS function:
void DFS(vector<int> Adj[], int n)
{
int visited[n], p[n], entry[n], leave[n];
int t = 0;
for (int i = 0; i < n; i++)
{
visited[i] = 0;
p[i] = -1;
}
for (int i = 0; i < n; i++)
{
if (!visited[i])
{
DFS_visit(i, Adj, visited, p, entry, leave, t);
}
}
Could you please tell me how I am supposed to pass the updated value of leave time to leave[i]? Thanks in advance!
I am new to C++ STL and have started Graph Theory recently.
After referring to https://www.geeksforgeeks.org/connected-components-in-an-undirected-graph/, I can count the number of connected components in an undirected, unweighted graph using DFS as:
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
int connected=0, temp1, temp2,n, p;
void DFS(int start, vector<int> v[],vector<int> &visited) {
visited[start] = 1;
for(int i= 0; i<v[start].size(); ++i) {
if(visited[v[start][i]] == 0)
DFS(v[start][i], v, visited);
}
}
int main() {
cin>>n>>p; // number of vertices and edges
vector<int> v[n+1], visited(n+1,0);
for(int i=0; i<p; ++i) {
cin>>temp1>>temp2;
v[temp1].push_back(temp2);
v[temp2].push_back(temp1);
}
connected = 0;
for(int i=1;i<=n;++i) {
if(visited[i] == 0 ) {
connected++;
DFS(i,v,visited);
}
}
cout<<connected<<endl;
return 0;
}
But how do we count the total number of nodes in each component?
For example: In this graph, see image there are 3 connected
components, with no. of nodes being 3, 2 , and 1 respectively.
You could maintain a dummy variable count with each call to DFS from main()
void DFS(int start, vector<int> v[],vector<int> &visited, int &count)
{
visited[start] = 1;
count++;
for(int i= 0; i<v[start].size(); ++i)
{
if(visited[v[start][i]] == 0)
DFS(v[start][i], v, visited);
}
}
and
for(int i=1;i<=n;++i)
{
if(visited[i] == 0 )
{
connected++;
int count=0;
DFS(i,v,visited,count);
cout<<"This component has "<<count<<" nodes"<<"\n";
}
}
Or you could refer to the change in visited vector(number of new 1's in it) after every call to DFS() from main()
you can maintain a global variable no_of_nodes which will be set to zero at start of dfs of each component and incremented by one when you visit each node in that component.
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
int connected=0, temp1, temp2,n, p;
int no_of_nodes=0;
void DFS(int start, vector<int> v[],vector<int> &visited) {
visited[start] = 1;
no_of_nodes++;
for(int i= 0; i<v[start].size(); ++i) {
if(visited[v[start][i]] == 0)
DFS(v[start][i], v, visited);
}
}
int main() {
cin>>n>>p; // number of vertices and edges
vector<int> v[n+1], visited(n+1,0);
for(int i=0; i<p; ++i) {
cin>>temp1>>temp2;
v[temp1].push_back(temp2);
v[temp2].push_back(temp1);
}
connected = 0;
vector<int>nodes;
for(int i=1;i<=n;++i) {
if(visited[i] == 0 ) {
connected++;
no_of_nodes=0;
DFS(i,v,visited);
nodes.push_back(no_of_nodes);
}
}
cout<<connected<<endl;
return 0;
}
how to find of what vertices is made cycle in undirected graph if there is only one cycle in graph?
I have code for finding cycle in graph, but right now I need code that will find of what vertices cycle is made.
Here is code(in C++) for finding cycle:
bool dfs(int x)
{
state[x] = 1;
for(int j = 0; j < ls[x].size(); j++)
{
if(state[ls[x][j]] == 1 and parent[x] != ls[x][j])
{
t = 0; // Graph contains cycle.
return t;
}
if(state[ls[x][j]] == 0)
{
parent[ls[x][j]] = x;
dfs(ls[x][j]);
}
}
}
void detect_cycle()
{
memset(state, 0, sizeof state);
memset(parent, 0, sizeof parent);
for(int i = 1; i <= n; i++)
if(state[i] == false)
dfs(i);
}
Thanks.
Here is the final code. Thanks guys.
bool dfs(int x)
{
state[x] = 1;
for(int j = 0; j < ls[x].size(); j++)
{
if(state[ls[x][j]] == 1 and parent[x] != ls[x][j])
{
if(t)
{
printf("Cycle entry: %d\n", ls[x][j]);
printf("Cycle contains: %d, %d ", ls[x][j], x);
int cycleNode = parent[x];
while(cycleNode != ls[x][j])
{
printf("%d ", cycleNode);
cycleNode = parent[cycleNode];
}
}
t = 0;
return t;
}
if(state[ls[x][j]] == 0)
{
parent[ls[x][j]] = x;
dfs(ls[x][j]);
}
}
}
A naive method - just throw away any node with degree 1, until all nodes have degree 2. This is the cycle in the graph.
If i'm right, then parent[] is an array (parent[i] is the number of the node that you vivted straight before you visited the i-th one).
Then you know that if the graph contains the cycle (you visit a node you have already visited), you know at least one node in the cycle (suppose its the k-th one). In this case, the parent[k] node also belongs to the cycle, and parent[parent[k]], and so on.
So, we get the next code:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <set>
#include <map>
using namespace std;
vector <int> state;
vector <vector <int> > ls; //graph
vector <int> parent;
bool t = 1;
int theNodeInTheCycle;
void dfs(int x)
{
state[x] = 1;
for(int j = 0; j < ls[x].size(); j++)
{
if(state[ls[x][j]] == 1 && parent[x] != ls[x][j])
{
parent[ls[x][j]] = x;
theNodeInTheCycle = ls[x][j]; //ls[x][j] belongs to the cycle since state[ls[x][j]]==1
t = 0;
}
if(state[ls[x][j]] == 0)
{
parent[ls[x][j]] = x;
dfs(ls[x][j]);
}
}
}
vector <int> GetCycle ()
{
vector <int> cycle;
int firstNodeInTheCycle = theNodeInTheCycle;
do
{
theNodeInTheCycle = parent[theNodeInTheCycle];
cycle.push_back (theNodeInTheCycle);
} while (theNodeInTheCycle != firstNodeInTheCycle);
reverse (cycle.begin (), cycle.end ()); //to get them in the right order
return cycle;
}
int main()
{
int n; cin>>n; //the number of nodes (from 0 to n-1)
int m; cin>>m; //the number of edges
state.resize (n);
ls.resize (n);
parent.resize (n);
for (int i = 0; i < m; ++i)
{
int a, b; cin>>a>>b;
ls[a].push_back(b);
ls[b].push_back(a);
}
for (int i = 0; i<n; ++i)
if (state[i]==0)
dfs(i);
if (t==0)
{
vector <int> cycle = GetCycle ();
for (int i = 0; i < cycle.size (); ++i)
cout<<cycle[i]<<" ";
cout<<"\n";
}
else cout<<"No cycle\n";
}
when you run dfs, if a vertex is marked when dfs() before, there must be a cycle.
A
/
B
| \
C E
\ /
D
if there is only one cycle in graph, the vertex marked before is the entry of cycle, as B below, whatever the start vertex of dfs is.
and in your code,
if(state[ls[x][j]] == 1 and parent[x] != ls[x][j])
{
t = 0; // Graph contains cycle.
return t;
}
in the first if() {},parent and t is unnecessary,change to:
if(state[ls[x][j]] == 1 and parent[x] != ls[x][j])
{
cout<<"cycle's entry:"<<j<<endl;
// Graph contains cycle.
return false;
}
besides,your code need a return true; outside the for of dfs().