For any unweighted or graph having equal weight shortest path between single source to all other vertices can be found using BFS in O(N)
//pseudocode
vector<vector<int> > adj // adjacency list
int d[n] // distance array
d[s]=0 // setting distance of source to 0
bool visited[n] // initialized to false
queue<int> q;
q.push(s);
visited[s]=true;
while(!q.empty())
{
int node=q.front();
q.pop();
for(auto child:adj[node])
{
if(visited[child]==false)
{
visited[child]=true;
d[child]=d[node]+1;
q.push(child);
}
}
}
Similarly if we have a weighted graph with non negative weight we can use dijkstra which run in
O(Vlog(E))
//pseudocode
vector<vector<int>> adj;
d[s] = 0;
set<pair<int, int>> q;
q.insert({0, s});
while (!q.empty()) {
int v = q.begin()->second;
q.erase(q.begin());
for (auto edge : adj[v]) {
int u = edge.first;
int w = edge.second;
if (d[v] + w < d[u]) {
q.erase({d[u], u});
d[u] = d[v] + w;
q.insert({d[u], u});
}
}
}Dijkstra uses a set or priority queue because at every iteration edge with smallest cost is required so an additional time of sorting the edges is involved at each step
Suppose we have a special weighted graph where each edge has a weight of 0 or 1 , here we can apply dijkstra as above but can we do any better?
The answer is yes we can use 0-1 BFS which is obtained by combining BFS with Dijkstra
In BFS we use queue in Dijkstra we use set in 0-1 BFS we use Deque, Deque allows insertion as well deletion from both ends in O(1)
Since we only have 0 and 1 as weight whenever we encounter an node which is connected by 0 weight edge we push that node at front of deque otherwise we push it at end of deque push nodes in this fashion always results in deque being sorted and we overcome the sorting required at each iteration during Dijkstra, the same technique can be generalized for any di-weighted graph push the node connected with smaller weight edge at front and larger weight at end
//pseudocode
vector<vector<int>> adj;
vector<int> d(n, INF);
d[s] = 0;
deque<int> q;
q.push_front(s);
while (!q.empty()) {
int v = q.front();
q.pop_front();
for (auto edge : adj[v]) {
int u = edge.first;
int w = edge.second;
if (d[v] + w < d[u]) {
d[u] = d[v] + w;
if (w == 1)
q.push_back(u);
else
q.push_front(u);
}
}
}Sample problems:
chef and reversing(codechef)
Problem statement : for any directed graph with n edges and m vertices what is minimum number of edges to be reversed to have a path from vertex 1 to vertex n
solution:
We will convert the graph into weighted graph for every edge from u to v in original graph we will define its weight as 0 and add a reversed edge from v to u with weight 1
Then apply 0-1 bfs using vertex 1 as source
The shortest path algorithm will always try to use as less reverse paths possible because they have higher weight than original edges.
//pseudocode
unordered_map<int,list<pair<int,int>> adj;
for(int k=0;k<n;k++)
{
int i,j;
cin>>i>>j;
adj[i].push_back(make_pair(j,0));
adj[j].push_back(make_pair(i,1));
}
deque<int> q;
int d[n+1]; // initialized to 1e9
d[1]=0;
q.push_front(1);
while(!q.empty())
{
int node=q.front();
q.pop_front();
for(auto neighbour:adj[node])
{
int x=neighbour.first;
int y=neighbour.second;
if(d[node]+y<d[x])
{
d[x]=d[node]+y;
if(y==0)
{
q.push_front(x);
}
else
{
q.push_back(x);
}
}
}
}
if(d[n]==1e9)
{
cout<<-1<<endl;
}
else
{
cout<<d[n]<<endl;
}
minimum cost to make at least one valid path
solution:
the problem is similar to above
Lets say for grid[i][j]=1 which means there is a path from current cell to right which is grid[i][j+1] So we will define weight of edge from grid[i][j] to grid[i][j+1] to 0 and add there 3 extra edge grid[i][j] to grid[i][j-1] , grid[i][j] to
grid[i-1][j], grid[i][j] to grid[i+1][j] with weight 1
We will do this for every cell keep the original edge with weight 0 and add 3 extra edges with weight 1
At end we will apply 0-1 BFS with with cell i=0,j=0 as source and print distance of bottom right cell