Aph 3-Notes
Aph 3-Notes
Bipartite Graph
A bipartite graph is a graph whose vertices can be divided into two disjoint sets so
that every edge connects two vertices from different sets (i.e. there are no edges
which connect vertices from the same set). These sets are usually called sides.
1
In the above graph, the nodes are marked with either Red Color or Blue Color. Now,
these colors can be represented as Sets. So according to the definition of Bipartite
graphs there should be no edge between two red vertices or two blue vertices. So the
above graph is clearly not Bipartite.
Now, let's take a look at another example
The above graph has no edge between the vertices of the same color (set), therefore, it
is a bipartite graph.
1. Use a col[] array which stores 0 or 1 for every node which denotes
opposite colors.
2. Call the function DFS from any node.
2
3. If the node u has not been visited previously, then assign !col[v] to col[u]
and call DFS again to visit nodes connected to u.
4. If at any point, color[u] is equal to col[v], then the node is not bipartite.
5. Modify the DFS function such that it returns a boolean value at the end.
#include<bits/stdc++.h>
using namespace std;
for(int v : adj[node]){
if(vis[v] == false){
bool result = dfs(v , col ^ 1);
return false;
}
int main(){
int n , m;
int a , b;
3
cin>>n>>m;
for(int i=0;i<m;i++){
cin>>a>>b;
adj[a].push_back(b);
adj[b].push_back(a);
}
for(int i=1;i<=n;i++)
if(vis[i] == false){
bool result = dfs(i , 0);
if(result == true){
flag = true;
break;
}
}
4
Bridges in a Graph
Problem Statement:
Given an undirected graph of V vertices and E edges. Your task is to find all the
bridges in the given undirected graph. A bridge in any graph is defined as an edge
which, when removed, makes the graph disconnected (or more precisely, increases
Approach:
and only if
○ Or none of the vertices v and its descendants in the DFS traversal tree
○ in[] - this stores the time when the vertex is first visited.
○ low[] - for every vertex u it stores the discovery time of the earliest
5
■ in[p]: where p is an ancestor of u in the dfs tree and have an
● Initially, we will initialize low[] to -1. We will also initialize one variable timer =
Code:
#include<bits/stdc++.h>
using namespace std;
vector<int> adj[N+1];
int in[N+1] , low[N+1];
int timer;
bool vis[N+1];
6
for(int v : adj[node]){
if(v == par) continue;
int main(){
#ifndef ONLINE_JUDGE
freopen("input.txt" , "r" , stdin);
freopen("output.txt" , "w" , stdout);
#endif
int n , m;
int a , b;
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>a>>b;
adj[a].push_back(b);
adj[b].push_back(a);
}
dfs(1 , -1);
7
Time Complexity:
O(E * (V + E)), where V is the number of vertices and E is the number of edges in the
graph.
In the worst case for each edge present in graph O(E), we will traverse the whole
Space Complexity:
In the worst case, extra space is required to store visited vertices O(V) and also an
Articulation Points
Introduction:
removing it (and edges through it) disconnects the graph. Articulation points are
failure would split the network into 2 or more components. They are useful for
8
Problem Statement:
You are given an undirected unweighted graph and you are supposed to find all
Approach:
The idea is to use DFS (Depth First Search). In DFS, we follow vertices in a tree form
called DFS tree. In DFS tree, a vertex u is the parent of another vertex v, if v is
2. u is not the root of DFS tree and it has a child v such that no vertex in the
subtree rooted with v has a back edge to one of the ancestors (in the DFS
tree) of u.
We do DFS traversal of given graph with additional code to find out Articulation
Points (APs). In DFS traversal, we maintain a parent[] array where parent[u] stores
parent of vertex u. Among the above-mentioned two cases, the first case is simple
to detect. For every vertex, count children. If currently visited vertex u is root
(parent[u] is NIL) and has more than two children, print it.
The second case is trickier. We maintain an array disc[] to store discovery time of
vertices. For every node u, we need to find out the earliest visited vertex (the vertex
9
with minimum discovery time) that can be reached from subtree rooted with u. So
Code:
#include<bits/stdc++.h>
using namespace std;
for(int v : adj[node]){
if(v == par) continue;
if(vis[v]){
low[node] = min(low[node] , in[v]);
}
else{
dfs(v , node) , child++;
if(par != -1 && low[v] >= in[node])
isArticulationPoint[node] = true;
low[node] = min(low[node] , low[v]);
}
}
10
}
int main(){
#ifndef ONLINE_JUDGE
freopen("input.txt" , "r" , stdin);
freopen("output.txt" , "w" , stdout);
#endif
int n , m;
int a , b;
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>a>>b;
adj[a].push_back(b);
adj[b].push_back(a);
}
dfs(1 , -1);
for(int i=1;i<=n;i++)
if(isArticulationPoint[i]) cout<<"Node "<<i<<" is articulation
point\n";
}
Time Complexity:
O(V+E), where V is the number of vertices and E is the number of edges in the
graph.
Space Complexity:
11
Strongly Connected Components
strongly connected subgraph. For example, there are 3 SCCs in the following graph.
Problem statement:
You are given an unweighted directed graph of 'V' vertices and 'E' edges. Your task
is to print all the strongly connected components (SCCs) present in the graph.
12
Approach:
Tarjan’s Algorithm:
● Tarjan’s algorithm can determine the SCCs using just a single DFS. Before
● The discovery time of a node is the time at which the node was discovered
during the DFS. This can be represented by an integer value which also
specifies the order in which the nodes are visited during the DFS.
● The low-link value of a node is the smallest (lowest) discovery time reachable
from that node during the DFS, including the node itself.
● For a SCC in a graph, every node which is a part of the SCC will have the same
low-link value. But this may not be true all the time.
● As the discovery time of a node depends on the order in which the graph is
traversed in a DFS, hence it may be possible that multiple nodes may have
the same low-link value even though they are a part of different SCC.
● This is where Tarjan’s SCC algorithm comes in. The algorithm maintains an
invariant which prevents the low-link values of two SCCs from interfering
● The invariant used is a stack, which is different from the stack being used for
DFS. The stack stores the nodes forming a subtree from which the SCC will be
found. Nodes are placed in the stack in the order in which they are visited.
But the nodes are removed only when a complete SCC is found.
Code:
13
#include<bits/stdc++.h>
using namespace std;
vector<int> adj[N];
for(int v : adj[node]){
if(vis[v]){
if(onStack[v]) low[node] = min(low[node] , in[v]);
}
else{
dfs(v);
low[node] = min(low[node] , low[v]);
}
}
if(in[node] == low[node]){
while(st.top() != node){
cout<<st.top()<<" ";
onStack[st.top()] = false;
st.pop();
}
cout<<st.top()<<" ";
onStack[st.top()] = false;
st.pop();
cout<<endl;
}
14
int main(){
#ifndef ONLINE_JUDGE
freopen("input.txt" , "r" , stdin);
freopen("output.txt" , "w" , stdout);
#endif
int t ,n ,m;
int a ,b;
cin>>t;
while(t--){
cin>>n>>m;
for(int i=0;i<n;i++){
adj[i].clear();
vis[i] = onStack[i] = false;
}
for(int i=0;i<m;i++){
cin>>a>>b;
adj[a].push_back(b);
}
for(int i=0;i<n;i++){
if(vis[i] == false) dfs(i);
}
}
}
Time Complexity:
O(V + E) per test case, where V is the number of vertices and E is the number of
In the worst case, Tarjan’s Algorithm performs a single DFS to obtain all the SCCs.
Space Complexity:
15
In the worst case, O(V) space is required for storing the low-link values, discovery
Edges In MST
Problem statement:
Your task is to determine the following for each edge of the given graph: whether it
is either included in any MST, included at least in one MST, or not included in any
MST.
Approach:
Let's take a look at Kruskal Algorithm which solve MST in O(m log m) time:-
● Then process each edges. if the edge connects two different connected
compoments, add this edge to MST then combine two compoments. Like
DSU.
● The main point is that only those edges with same weight may replace each
other in MST.
● First of all, sort edges as what Kruskal do. To get the answer, we construct
MST in weight non-decreasing order, and process all edges with same weight
together.
● Now on each step we are to face some edges with same weight x and a
16
● Note that for an edge, what points it connects does not matter, we only need
● Now build a new graph G', each point in G' is a connected compoment in the
connected before.
loop(connects the same compoment), this edge must not appear in any
MSTs.
compoment in G' spilt into two. We call these edges bridge), V must be in any
of MST. All edges left can appear in some MSTs, but not any.
● Now we can simply use Tarjan’s algorithm to get the answer quickly.
Code:
#include<bits/stdc++.h>
using namespace std;
struct Edge{
int a , b , w;
int index;
};
//list of edges
Edge edges[N+1];
//for dsu
int _par[N+1];
17
//for graph
vector<pair<int,int> > adj[N+1];
//for bridges
int in[N+1] , low[N+1] , timer;
bool vis[N+1];
if(a == b) return;
result[index] = 1;
adj[a].push_back({b , index});
adj[b].push_back({a , index});
}
adj[a].clear();
adj[b].clear();
//merge
if(a != b) _par[a] = b;
}
18
void dfs(int node , int edgeIndex){
in[node] = low[node] = timer++;
vis[node] = true;
for(pair<int,int> e : adj[node]){
int index = e.second;
int v = e.first;
if(vis[v]){
low[node] = min(low[node] , in[v]);
}else{
dfs(v , index);
low[node] = min(low[node] , low[v]);
}
}
if(edgeIndex != 0){
if(in[node] == low[node]) result[edgeIndex] = 2;
}
int main(){
// #ifndef ONLINE_JUDGE
// freopen("input.txt" , "r" , stdin);
// freopen("output.txt" , "w" , stdout);
// #endif
int n , m;
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>edges[i].a>>edges[i].b>>edges[i].w;
edges[i].index = i;
19
}
int i = 1;
while(i <= m){
int j;
//STEP 1
for(j=i; edges[i].w == edges[j].w ; j++)
addEdge(edges[j].a , edges[j].b , edges[j].index);
i = j;
for(int i=1;i<=m;i++){
if(result[i] == 0) cout<<"none\n";
else
if(result[i] == 1) cout<<"at least one\n";
else cout<<"any\n";
}
}
Time Complexity:
20
Space Complexity:
21