Given a graph consisting of vertices numbered from 1 to N and having M bidirectional edges connecting vertices u and v. Let P denote an entrance vertex. N elements are numbered from 1 to N and inserted into the graph from the entrance P (1<=P<=N) in ascending order. A filled vertex is a vertex where an element is already placed. An element e (1<=e<=N) is said to be placed if it can reach the eth vertex starting from vertex P without crossing any other filled vertex; otherwise, the element cannot be placed and is skipped; hence the eth vertex remains unfilled. Calculate the number of filled vertex/placed elements in the graph.
Examples:
Input: N = 4, M = 4, P = 4, Edges = {{ 1, 3 }, { 1, 4 }, { 2, 3 }, { 2, 4 }} Output: 3 Explanation: Lets insert the elements in ascending order from 1 to N
- E = 1. The element is inserted from 4->1. So count = 1
- E = 2. The element is inserted from 4->2. So count = 2
- E = 3. The two paths from P i.e. 4 to 3 are 4->1->3 and 4->2->3. In first path the element cannot be traversed through 1 as it is already filled. Similarly for the second path the element cannot travel as the vertex 2 is already filled. So skip element 3.
- E = 4. The element number if the starting vertex and is empty so vertex 4 is filled. Count = 3
Input: N = 5, M = 4, P = 3, Edges = {{1, 2 }, { 2, 3 }, { 3, 4 }, { 4, 5}} Output: 3 Explanation: Lets insert the elements in ascending order from 1 to N
- E = 1. Traverse from 3->2->1 and place the element. Vertex 1 is now filled. Count = 1
- E = 2. Traverse from 3->2 and place the element. Vertex 2 is now filled. Count = 2
- E = 3. It is the starting vertex where the element is to be placed. So vertex 3 is filled. Count = 3
- E = 4. Starting vertex is 3 ie. P and now vertex 3 is already filled. Hence from P no more vertices can be visited to be filled by the elements.
- E = 5. Similar case as of E = 4 it cannot be visited. Hence the final count is Count = 3
Approach: To solve the problem using BFS/DFS follow the below idea:
Problem translates to remove the vertex i if it can be reached from vertex P otherwise skip the element. Inshort for each vertex from 1 to N we have to check is there exist a path to vertex i from vertex P. If there exist a path remove that vertex and then check for the next vertex in ascending order on the modified graph. This check can be done using BFS or DFS for each vertex.
Follow the steps to code:
- The solve function builds the adjacency list representation of the graph and calls the
BFS function to determine the number of filled vertices.
- Once the adjacency list is built BFS call is made.
- In the BFS,
- Vector visited, and isRemoved is initialized to false. Visited keeps track of the visited vertices and isRemoved keeps track of the filled vertices that can be removed from the graph.
- Each element e is then iterated in ascending order
- Each neighboring vertices of vertex U from the queue are then iterated such that the vertices are not visited yet and are also present inside the graph, i.e. isRemoved is set to false for a particular vertex.
- If the vertex e is reachable from vertex P, then isRemoved for the vertex e is marked True.
- Finally, count the vertices for which isRemoved is true and return the count.
- Output the final count
Below is the implementation of the above idea:
C++
#include <bits/stdc++.h>
using namespace std;
int BFS( int N, int P, vector<vector< int > >& adj)
{
queue< int > Q;
vector< bool > vis, isRemoved(N + 1, 0);
for ( int e = 1; e <= N; e++) {
Q = queue< int >();
Q.push(P);
vis.assign(N + 1, 0);
vis[P] = 1;
if (isRemoved[P]) {
continue ;
}
while (!Q.empty()) {
int u = Q.front();
Q.pop();
for ( auto v : adj[u]) {
if (vis[v] == 0 and isRemoved[v] == 0) {
vis[v] = 1;
Q.push(v);
}
}
}
if (vis[e]) {
isRemoved[e] = 1;
}
}
int count = 0;
for ( int i = 1; i <= N; i++) {
if (isRemoved[i]) {
count++;
}
}
return count;
}
void solve( int N, int M, int P, vector<vector< int > >& edges)
{
vector<vector< int > > adj(N + 1);
for ( auto edge : edges) {
int u = edge[0], v = edge[1];
adj[u].push_back(v);
adj[v].push_back(u);
}
int filledVertices = BFS(N, P, adj);
cout << "Number of filled vertices are: "
<< filledVertices << "\n";
}
int main()
{
int N, M, P;
N = 4, M = 4, P = 4;
vector<vector< int > > edges
= { { 1, 3 }, { 1, 4 }, { 2, 3 }, { 2, 4 } };
solve(N, M, P, edges);
return 0;
}
|
Java
import java.util.*;
public class GFG {
static int BFS( int N, int P, List<List<Integer>> adj) {
Queue<Integer> Q = new LinkedList<>();
List<Boolean> vis = new ArrayList<>();
List<Boolean> isRemoved = new ArrayList<>(Collections.nCopies(N + 1 , false ));
for ( int e = 1 ; e <= N; e++) {
Q.clear();
Q.add(P);
vis.clear();
vis.addAll(Collections.nCopies(N + 1 , false ));
vis.set(P, true );
if (isRemoved.get(P)) {
continue ;
}
while (!Q.isEmpty()) {
int u = Q.poll();
for ( int v : adj.get(u)) {
if (!vis.get(v) && !isRemoved.get(v)) {
vis.set(v, true );
Q.add(v);
}
}
}
if (vis.get(e)) {
isRemoved.set(e, true );
}
}
int count = 0 ;
for ( int i = 1 ; i <= N; i++) {
if (isRemoved.get(i)) {
count++;
}
}
return count;
}
static void solve( int N, int M, int P, List<List<Integer>> edges) {
List<List<Integer>> adj = new ArrayList<>();
for ( int i = 0 ; i <= N; i++) {
adj.add( new ArrayList<>());
}
for (List<Integer> edge : edges) {
int u = edge.get( 0 );
int v = edge.get( 1 );
adj.get(u).add(v);
adj.get(v).add(u);
}
int filledVertices = BFS(N, P, adj);
System.out.println( "Number of filled vertices are: " + filledVertices);
}
public static void main(String[] args) {
int N, M, P;
N = 4 ;
M = 4 ;
P = 4 ;
List<List<Integer>> edges = new ArrayList<>();
edges.add(Arrays.asList( 1 , 3 ));
edges.add(Arrays.asList( 1 , 4 ));
edges.add(Arrays.asList( 2 , 3 ));
edges.add(Arrays.asList( 2 , 4 ));
solve(N, M, P, edges);
}
}
|
Python3
from collections import deque
def bfs(N, P, adj):
queue = deque()
is_removed = [ False ] * (N + 1 )
count = 0
for e in range ( 1 , N + 1 ):
queue.clear()
queue.append(P)
visited = [ False ] * (N + 1 )
visited[P] = True
if is_removed[P]:
continue
while queue:
u = queue.popleft()
for v in adj[u]:
if not visited[v] and not is_removed[v]:
visited[v] = True
queue.append(v)
if visited[e]:
is_removed[e] = True
for e in range ( 1 , N + 1 ):
if is_removed[e]:
count + = 1
return count
def solve(N, M, P, edges):
adj = [[] for _ in range (N + 1 )]
for u, v in edges:
adj[u].append(v)
adj[v].append(u)
filled_vertices = bfs(N, P, adj)
print ("Number of filled vertices are:", filled_vertices)
if __name__ = = "__main__":
N, M, P = 4 , 4 , 4
edges = [[ 1 , 3 ], [ 1 , 4 ], [ 2 , 3 ], [ 2 , 4 ]]
solve(N, M, P, edges)
|
C#
using System;
using System.Collections.Generic;
using System.Linq;
public class GFG
{
static int BFS( int N, int P, List<List< int >> adj)
{
Queue< int > Q = new Queue< int >();
List< bool > vis = new List< bool >( new bool [N + 1]);
List< bool > isRemoved = Enumerable.Repeat( false , N + 1).ToList();
for ( int e = 1; e <= N; e++)
{
Q.Clear();
Q.Enqueue(P);
vis.Clear();
vis.AddRange(Enumerable.Repeat( false , N + 1));
vis[P] = true ;
if (isRemoved[P])
{
continue ;
}
while (Q.Count > 0)
{
int u = Q.Dequeue();
foreach ( int v in adj[u])
{
if (!vis[v] && !isRemoved[v])
{
vis[v] = true ;
Q.Enqueue(v);
}
}
}
if (vis[e])
{
isRemoved[e] = true ;
}
}
int count = 0;
for ( int i = 1; i <= N; i++)
{
if (isRemoved[i])
{
count++;
}
}
return count;
}
static void solve( int N, int M, int P, List<List< int >> edges)
{
List<List< int >> adj = new List<List< int >>();
for ( int i = 0; i <= N; i++)
{
adj.Add( new List< int >());
}
foreach (List< int > edge in edges)
{
int u = edge[0];
int v = edge[1];
adj[u].Add(v);
adj[v].Add(u);
}
int filledVertices = BFS(N, P, adj);
Console.WriteLine( "Number of filled vertices are: " + filledVertices);
}
public static void Main( string [] args)
{
int N, M, P;
N = 4;
M = 4;
P = 4;
List<List< int >> edges = new List<List< int >>
{
new List< int > { 1, 3 },
new List< int > { 1, 4 },
new List< int > { 2, 3 },
new List< int > { 2, 4 }
};
solve(N, M, P, edges);
}
}
|
Javascript
function BFS(N, P, adj) {
const Q = [];
const vis = Array(N + 1).fill( false );
const isRemoved = Array(N + 1).fill( false );
for (let e = 1; e <= N; e++) {
Q.length = 0;
Q.push(P);
vis.fill( false );
vis[P] = true ;
if (isRemoved[P]) {
continue ;
}
while (Q.length > 0) {
const u = Q.shift();
for (const v of adj[u]) {
if (!vis[v] && !isRemoved[v]) {
vis[v] = true ;
Q.push(v);
}
}
}
if (vis[e]) {
isRemoved[e] = true ;
}
}
let count = 0;
for (let i = 1; i <= N; i++) {
if (isRemoved[i]) {
count++;
}
}
return count;
}
function solve(N, M, P, edges) {
const adj = Array.from({ length: N + 1 }, () => []);
for (const edge of edges) {
const u = edge[0];
const v = edge[1];
adj[u].push(v);
adj[v].push(u);
}
const filledVertices = BFS(N, P, adj);
console.log( "Number of filled vertices are:" , filledVertices);
}
const N = 4;
const M = 4;
const P = 4;
const edges = [
[1, 3],
[1, 4],
[2, 3],
[2, 4]
];
solve(N, M, P, edges);
|
Output
Number of filled vertices are: 3
Time Complexity: O(N*(N+M)) Auxiliary Space: O(N)
Efficient Approach: Using Dijkstra Algorithm
- The key idea here to note is that we can fill the vertex v if it can be traversed from vertices greater than or equal to v. Also we are using a single source vertex to check if we can traverse each vertex in ascending order. Then vertex v can only be filled if it is traversed from S by vertices greater than or equal to V which means for each vertex v we can store the maximum minimum vertex that can be traversed. If this value is greater than or equal to v then the vertex can be filled. Else it cannot be filled as to travel to that vertex from S we have to traverse a vertex which is smaller than v. And the vertex smaller than v is already processed as the vertices have to be filled in ascending order.
- To ensure that we traverse through the larger values and then to smaller ones, we can use the concept from Dijkstra to use a priority queue instead of a regular one. By doing this, we process the vertices in the order of decreasing the maximum, minimum value to ensure that we only consider the paths that maximize the minimum index encountered. Overall, the priority queue helps select the vertices in the order that maximizes the minimum index encountered along the paths.
Follow the steps to code:
- The solve function builds the adjacency list representation of the graph and calls the
BFS function to determine the number of filled vertices.
- Once the adjacency list is built, a Dijkstra call is made.
- In the Dijkstra,
- Initialize two vectors vis and dist. Vis keeps track of whether the vertex is previously visited, and dist array stores the maximum minimum vertex value for vertex i. dist[i] denotes the maximum of the minimum vertices that must be traversed to reach vertex i.
- Declare a priority queue of type max heap to extract the vertices in decreasing order of minimum vertex so that to get the maximum and minimum value and iterate the graph in the order of decreasing the maximum and minimum value to ensure that we only consider the paths that maximize the minimum index encountered.
- While visiting the neighbors
- Update the maximum minimum value for the neighbors
- If the neighbor’s current maximum minimum value is smaller than the calculated value, update it
- Now if the dist[i] >= i, then the vertex i is reachable from vertex S. This is because if the dist[i] was less than i, then vertex dist[i] will be filled first as we are inserting the elements in the ascending order. And hence as the only path to vertex i was from dist[i] we could not reach vertex i and had to skip it.
- Store the count of such vertices.
- Output the count.the
Below is the implementation of the above idea:
C++
#include <bits/stdc++.h>
using namespace std;
int Dijkstra( int N, int P, vector<vector< int > >& adj)
{
vector< int > dist(N + 1, 0);
vector< bool > vis(N + 1, 0);
priority_queue<pair< int , int > > pq;
pq.push({ P, P });
dist[P] = P;
while (!pq.empty()) {
int dis = pq.top().first;
int u = pq.top().second;
pq.pop();
if (vis[u]) {
continue ;
}
vis[u] = 1;
for ( auto v : adj[u]) {
int d = min(dis, v);
if (dist[v] < d) {
dist[v] = d;
pq.push({ d, v });
}
}
}
int count = 0;
for ( int i = 1; i <= N; i++) {
if (i <= dist[i]) {
count++;
}
}
return count;
}
void solve( int N, int M, int P, vector<vector< int > >& edges)
{
vector<vector< int > > adj(N + 1);
for ( auto edge : edges) {
int u = edge[0], v = edge[1];
adj[u].push_back(v);
adj[v].push_back(u);
}
int filledVertices = Dijkstra(N, P, adj);
cout << "Number of filled vertices are: "
<< filledVertices << "\n";
}
int main()
{
int N, M, P;
N = 4, M = 4, P = 4;
vector<vector< int > > edges
= { { 1, 3 }, { 1, 4 }, { 2, 3 }, { 2, 4 } };
solve(N, M, P, edges);
return 0;
}
|
Java
import java.util.*;
public class Main {
static int Dijkstra( int N, int P, List<List<Integer>> adj) {
int [] dist = new int [N + 1 ];
Arrays.fill(dist, 0 );
boolean [] vis = new boolean [N + 1 ];
PriorityQueue<Pair<Integer, Integer>> pq = new PriorityQueue<>((a, b) -> b.getKey() - a.getKey());
pq.offer( new Pair<>(P, P));
dist[P] = P;
while (!pq.isEmpty()) {
Pair<Integer, Integer> top = pq.poll();
int dis = top.getKey();
int u = top.getValue();
if (vis[u]) {
continue ;
}
vis[u] = true ;
for ( int v : adj.get(u)) {
int d = Math.min(dis, v);
if (dist[v] < d) {
dist[v] = d;
pq.offer( new Pair<>(d, v));
}
}
}
int count = 0 ;
for ( int i = 1 ; i <= N; i++) {
if (i <= dist[i]) {
count++;
}
}
return count;
}
static void solve( int N, int M, int P, List<List<Integer>> edges) {
List<List<Integer>> adj = new ArrayList<>();
for ( int i = 0 ; i <= N; i++) {
adj.add( new ArrayList<>());
}
for (List<Integer> edge : edges) {
int u = edge.get( 0 );
int v = edge.get( 1 );
adj.get(u).add(v);
adj.get(v).add(u);
}
int filledVertices = Dijkstra(N, P, adj);
System.out.println( "Number of filled vertices are: " + filledVertices);
}
public static void main(String[] args) {
int N, M, P;
N = 4 ;
M = 4 ;
P = 4 ;
List<List<Integer>> edges = new ArrayList<>();
edges.add(Arrays.asList( 1 , 3 ));
edges.add(Arrays.asList( 1 , 4 ));
edges.add(Arrays.asList( 2 , 3 ));
edges.add(Arrays.asList( 2 , 4 ));
solve(N, M, P, edges);
}
static class Pair<K, V> {
private K key;
private V value;
public Pair(K key, V value) {
this .key = key;
this .value = value;
}
public K getKey() {
return key;
}
public V getValue() {
return value;
}
}
}
|
Python3
import heapq
def dijkstra(N, P, adj):
dist = [ 0 ] * (N + 1 )
vis = [ False ] * (N + 1 )
pq = [(P, P)]
dist[P] = P
while pq:
dis, u = heapq.heappop(pq)
if vis[u]:
continue
vis[u] = True
for v in adj[u]:
d = min (dis, v)
if dist[v] < d:
dist[v] = d
heapq.heappush(pq, (d, v))
count = 0
for i in range ( 1 , N + 1 ):
if i < = dist[i]:
count + = 1
return count
def solve(N, M, P, edges):
adj = [[] for _ in range (N + 1 )]
for u, v in edges:
adj[u].append(v)
adj[v].append(u)
filledVertices = dijkstra(N, P, adj)
print ("Number of filled vertices are:", filledVertices)
if __name__ = = "__main__":
N, M, P = 4 , 4 , 4
edges = [[ 1 , 3 ], [ 1 , 4 ], [ 2 , 3 ], [ 2 , 4 ]]
solve(N, M, P, edges)
|
C#
using System;
using System.Collections.Generic;
public class MainClass
{
static int Dijkstra( int N, int P, List<List< int >> adj)
{
int [] dist = new int [N + 1];
bool [] vis = new bool [N + 1];
PriorityQueue<( int , int )> pq = new PriorityQueue<( int , int )>( new MaxMinComparer());
dist[P] = P;
pq.Enqueue((P, P));
while (pq.Count > 0)
{
( int dis, int u) = pq.Dequeue();
if (vis[u])
continue ;
vis[u] = true ;
foreach ( int v in adj[u])
{
int d = Math.Min(dis, v);
if (dist[v] < d)
{
dist[v] = d;
pq.Enqueue((d, v));
}
}
}
int count = 0;
for ( int i = 1; i <= N; i++)
{
if (i <= dist[i])
count++;
}
return count;
}
static void Solve( int N, int M, int P, List<List< int >> edges)
{
List<List< int >> adj = new List<List< int >>();
for ( int i = 0; i <= N; i++)
{
adj.Add( new List< int >());
}
foreach (List< int > edge in edges)
{
int u = edge[0];
int v = edge[1];
adj[u].Add(v);
adj[v].Add(u);
}
int filledVertices = Dijkstra(N, P, adj);
Console.WriteLine( "Number of filled vertices are: " + filledVertices);
}
public static void Main( string [] args)
{
int N = 4, M = 4, P = 4;
List<List< int >> edges = new List<List< int >>
{
new List< int > { 1, 3 },
new List< int > { 1, 4 },
new List< int > { 2, 3 },
new List< int > { 2, 4 }
};
Solve(N, M, P, edges);
}
}
public class MaxMinComparer : IComparer<( int , int )>
{
public int Compare(( int , int ) x, ( int , int ) y)
{
return y.Item1.CompareTo(x.Item1);
}
}
public class PriorityQueue<T>
{
private readonly List<T> heap;
private readonly IComparer<T> comparer;
public PriorityQueue() : this (Comparer<T>.Default)
{
}
public PriorityQueue(IComparer<T> comparer)
{
this .heap = new List<T>();
this .comparer = comparer;
}
public int Count => heap.Count;
public void Enqueue(T item)
{
heap.Add(item);
int i = heap.Count - 1;
while (i > 0)
{
int parent = (i - 1) / 2;
if (comparer.Compare(heap[parent], item) >= 0)
break ;
heap[i] = heap[parent];
i = parent;
}
heap[i] = item;
}
public T Dequeue()
{
int n = heap.Count - 1;
T result = heap[0];
T item = heap[n];
heap.RemoveAt(n);
if (n == 0)
return result;
int i = 0;
while ( true )
{
int left = i * 2 + 1;
if (left >= n)
break ;
int right = left + 1;
int child = (right >= n || comparer.Compare(heap[left], heap[right]) >= 0) ? left : right;
if (comparer.Compare(item, heap[child]) >= 0)
break ;
heap[i] = heap[child];
i = child;
}
heap[i] = item;
return result;
}
public T Peek()
{
return heap[0];
}
}
|
Javascript
function Dijkstra(N, P, adj) {
let dist = new Array(N + 1).fill(0);
let vis = new Array(N + 1).fill( false );
let pq = [];
pq.push([P, P]);
dist[P] = P;
while (pq.length > 0) {
let [dis, u] = pq.pop();
if (vis[u]) {
continue ;
}
vis[u] = true ;
for (let v of adj[u]) {
let d = Math.min(dis, v);
if (dist[v] < d) {
dist[v] = d;
pq.push([d, v]);
}
}
}
let count = 0;
for (let i = 1; i <= N; i++) {
if (i <= dist[i]) {
count++;
}
}
return count;
}
function solve(N, M, P, edges) {
let adj = new Array(N + 1).fill().map(() => []);
for (let edge of edges) {
let [u, v] = edge;
adj[u].push(v);
adj[v].push(u);
}
let filledVertices = Dijkstra(N, P, adj);
console.log( "Number of filled vertices are: " + filledVertices);
}
let N = 4,
M = 4,
P = 4;
let edges = [
[1, 3],
[1, 4],
[2, 3],
[2, 4]
];
solve(N, M, P, edges);
|
Output
Number of filled vertices are: 3
Time Complexity: O(N*logN) Auxiliary Space: O(N)
|