Finding Connectivity in a Graph - algorithm

I watched this Princeton University connected components tutorial and tried to run the code given on my computer (skip to 13 mins for code). The code should figure out all the different connected components of the graph and assign each vertex an 'id' which identifies which component it belongs to. I made a sample graph to test it, see here for:
![visual representation][1]
When I run the code below, it prints out the ids to be 0,0,1,2,3 but they should be 0,0,0,1,1. Any ideas what I'm doing wrong?
public class ConnectedComponents {
public boolean[] marked;
public int[] id;
public int count;
public ConnectedComponents() {
//Make a Graph with 5 vertices, and 4 edges
Graph g = new Graph(5, false, false);
g.addEdge(0, 1); g.addEdge(0, 2);g.addEdge(1, 2);
g.addEdge(3, 4);
int numVertices = g.getNumberOfVertices();
marked = new boolean[numVertices];
id = new int[numVertices];
for(int v = 0; v < numVertices; v++) {
if(!marked[v]) {
dfs(g, v);
count++;
}
}
}
public void dfs(Graph g, int v) {
marked[v] = true;
id[v] = count;
// loops through each vertex that's connected to v
for(int w: g.getEdgeMatrix()[v]) {
if(!marked[w]) {
dfs(g, w);
}
}
}
public int id(int v) {
return id[v];
}
public static void main(String [] args){
ConnectedComponents cc = new ConnectedComponents();
for(int i = 0; i < cc.id.length; i++) {
System.out.println(cc.id[i]);
}
}
}
https://i.stack.imgur.com/vhTxD.jpg

Because of the implementation of addEdge, your DFS is effectively operating on a directed graph. Change it to add the reverse edges.

Related

Problem with DFS graph algorithm, wrong loops found

I want to create an algorithm to understand how many closed areas there are in a graph with the relative points, at the moment the problem is that it finds almost all the loops, using a DFS algorithm. However, a problem arises
This is my actual code,momentarily done on processing for instant video feedback:
import java.util.Iterator;
import java.util.LinkedList;
class Graph {
int white = 0, gray = 1, black = 2;
ArrayList<ArrayList<Integer>> path = new ArrayList<ArrayList<Integer>>();
int V;
LinkedList<Integer>[] adj;
LinkedList<Integer>[] cycles;
LinkedList<PVector> points = new LinkedList<PVector>();
int num_cycles = 0;
Graph(int v) {
V = v;
adj = new LinkedList[V];
cycles = new LinkedList[V];
for (int i = 0; i < V; i++) {
adj[i] = new LinkedList();
cycles[i] = new LinkedList();
}
}
void DFSCycleUtil(int source, int parent, int[] colors, int[] parents) {
if (colors[source] == gray) {
System.out.println("Cycle");
path.add(new ArrayList<Integer>());
int curr_parent = parent;
cycles[num_cycles].add(source);
System.out.println(source);
path.get(num_cycles).add(source);
while (curr_parent != source) {
cycles[num_cycles].add(curr_parent);
path.get(num_cycles).add(curr_parent);
System.out.println(curr_parent);
curr_parent = parents[curr_parent];
}
num_cycles++;
return;
} else if (colors[source] == black) {
return;
}
parents[source] = parent;
colors[source] = gray;
Iterator<Integer> i = adj[source].listIterator();
while (i.hasNext()) {
int n = i.next();
if (n != parent) {
DFSCycleUtil(n, source, colors, parents);
}
}
colors[source] = black;
}
void DFSCycle() {
int colors[] = new int[V];
int parents[] = new int[V];
for (int i = 0; i < V; i++) {
colors[i] = white;
}
for (int i = 0; i < V; i++) {
if (colors[i] == white) {
DFSCycleUtil(i, -1, colors, parents);
}
}
}
void addEdge(int u, int v) {
adj[u].add(v);
adj[v].add(u);
}
void addPoint(int x, int y){
points.add(new PVector(x,y));
}
void drawGraph(){
for(int i = 0; i<points.size();i++){
circle(points.get(i).x,points.get(i).y,10);
text(i+1,points.get(i).x,points.get(i).y-5);
Iterator<Integer> in = adj[i+1].listIterator();
print(i + ": \n");
while (in.hasNext()) {
int t = in.next();
line(points.get(i).x,points.get(i).y,points.get(t-1).x,points.get(t-1).y);
}
}
for(int i = 0; i<path.size();i++){
fill(10,10,random(255));
beginShape();
for(int j = 0; j<path.get(i).size(); j++){
vertex(points.get(path.get(i).get(j)-1).x, points.get(path.get(i).get(j)-1).y);
}
endShape(CLOSE);
}
}
}
void setup(){
size(500,500);
Graph g = new Graph(9);
g.addEdge(1,2);
g.addEdge(1,3);
g.addEdge(3,2);
g.addEdge(3,4);
g.addEdge(5,2);
g.addEdge(5,6);
g.addEdge(4,2);
g.addEdge(4,6);
g.addEdge(4,5);
g.addPoint(100,50);
g.addPoint(150,50);
g.addPoint(100,100);
g.addPoint(150,100);
g.addPoint(200,50);
g.addPoint(200,100);
g.DFSCycle();
g.drawGraph();
}
The problem is that it also finds areas that cover other previously found areas, and I don't know how to avoid it.
I would like to know first if there is a better method than the one I am using, and then how I can solve my need.
Thanks in advance
Example images:
This is my actual result:
And this would be my final result:

Knight on Chess Board - Shortest Path

I'm trying to solve this problem: https://www.interviewbit.com/problems/knight-on-chess-board/#
Basically, you're given a board, a start point and an end point and have to find the shortest path. I'm trying to do BFS on the the board using the 8 possible moves a knight can make and returning the number of moves it took, or -1 if there was no solution. I'm getting a run time out of memory error. I'm not sure where the error (or potential errors) are occurring.
Edit: Previously I was getting an error because I forgot got to mark nodes as visited. I've added that in but I'm still not getting the right answer.
public class Solution {
private class Node {
int row;
int col;
int count;
public Node() {
this.row = 0;
this.col = 0;
this.count = 0;
}
public Node(int row, int col, int count) {
this.row = row;
this.col = col;
this.count = count;
}
}
public int knight(int A, int B, int sr, int sc, int er, int ec) {
int[][] matrix = new int[A][B];
Queue<Node> q = new LinkedList<>(); //linkedlist??
Node n = new Node(sr, sc, 0);
q.add(n);
matrix[sr][sc] = -1;
final int[][] SHIFTS = {
{-2,1},
{-2,-1},
{2,1},
{2,-1},
{-1,2},
{-1,-2},
{1,2},
{1,-2}
};
int count = 0;
while(!q.isEmpty()) {
Node cur = q.remove();
if(cur.row == er && cur.col == ec) {
return cur.count;
}
for(int[] i : SHIFTS) {
if(canTraverse(matrix, cur.row + i[0], cur.col + i[1])) {
matrix[cur.row + i[0]][cur.col + i[1]] = -1;
q.add(new Node(cur.row + i[0], cur.col + i[1], cur.count + 1));
}
}
}
return -1;
}
public static boolean canTraverse(int[][] matrix, int sr, int sc) {
if(sr < 0 || sr >= matrix.length || sc < 0 || sc >= matrix[sr].length || matrix[sr][sc] == -1) {
return false;
}
return true;
}
}
BFS algorithm needs to mark every visited position (node) to work properly. Else, such code could cause (almost certainly) runtime error or memory limit exceded (in short terms: A calls B and B calls A).
Solution: Create a boolean array and mark the nodes at the time they enter to the queue and you are done.

Print edges of a cycle in an undirected graph

I have an undirected graph which gets loaded as an adjacency matrix. I have a method to detect a cycle in a graph using BFS algorithm. What I am trying to achieve is to print all the edges in a way that they indicate a cycle which has been found.
I am able to print all the edges in a graph, but I am unable to print only those edges which create a cycle. How do I make it work?
Here is the graph implementation:
Edge:
public class Edge {
int source, dest;
public Edge(int source, int dest) {
this.source = source;
this.dest = dest;
}
}
Graph:
public class Graph {
// A List of Lists to represent an adjacency list
// Each insideList contains pointers to the next vertex
// list with an index of 1 (vertex 1) contains elements 2 and 3 (where 2, 3 are vertices connected to 1)
List<List<Integer>> adjList = null;
// Constructor
public Graph(List<Edge> edges, int N) {
adjList = new ArrayList<>(N);
for (int i = 0; i < N; i++) {
adjList.add(i, new ArrayList<>());
}
// add edges to the undirected graph
for (Edge edge : edges) {
int src = edge.source;
int dest = edge.dest;
adjList.get(src).add(dest);
adjList.get(dest).add(src);
}
}
}
Node:
public class Node {
int v, parent;
public Node(int v, int parent) {
this.v = v;
this.parent = parent;
}
}
Algorithm and test:
public class GraphTest {
// Perform BFS on graph starting from vertex src and
// returns true if cycle is found in the graph
// while traversing the graph, it should display the edges which create a cycle, but I am unable to do it (the result is wrong)
public static boolean BFS(Graph graph, int src, int N) {
// stores booleans if a vertex is discovered or not
boolean[] discovered = new boolean[N];
// mark source vertex as discovered
discovered[src] = true;
// create a queue used to do BFS and
// push source vertex into the queue
Queue<Node> q = new ArrayDeque<>();
q.add(new Node(src, -1));
// run till queue is not empty
while (!q.isEmpty()) {
// pop front node from queue and print it
Node node = q.poll();
// do for every edge (v -> u)
for (int u : graph.adjList.get(node.v)) {
if (!discovered[u]) {
// mark it as discovered
discovered[u] = true;
// construct the queue node containing info
// about vertex and push it into the queue
System.out.println(node.v + " -- " + u);
q.add(new Node(u, node.v));
}
// u is discovered and u is not a parent
else if (u != node.parent) {
// we found a cross-edge ie. cycle is found
return true;
}
}
}
// No cross-edges found in the graph
return false;
}
// Check if an undirected graph contains cycle or not
public static void main(String[] args) {
// In my case I load an adjacency matrix from file and then perform an action to create Edges.
// 0 1 1 0
// 1 0 1 0
// 1 1 0 1
// 0 0 1 0
// Edge(1, 2), Edge(2, 3), Edge(3, 1), Edge(3, 4)
// Edge(3, 1) introduces a cycle in the graph
List<Edge> edges = new ArrayList<Edge>();
ArrayList<ArrayList<Integer>> matrixList = loadFromFile(filePath);
System.out.println("Graph: (Adjacency Matrix)");
for (int i = 0; i < matrixList.size(); i++) {
for (int j = 0; j < matrixList.size(); j++) {
System.out.print(matrixList.get(i).get(j) + " ");
}
System.out.println();
}
System.out.println("All the edges: ");
for (int i = 0; i < matrixList.size(); i++) {
// ' + 1' is added so as to start vertices from 1 instead of 0
int temp = i + 1;
for (int j = 0; j < matrixList.size(); j++) {
if (matrixList.get(i).get(j) == 1) {
System.out.println(temp + "--" + (j + 1) + " ");
// each edge is added one-way only since it is an undirected graph
// if Edge(1,3) is already present, Edge(3,1) is not added
boolean isFound = false;
for (Edge e : edges) {
if (e.dest == temp && e.source == (j + 1)) {
isFound = true;
}
}
if (!isFound)
edges.add(new Edge(temp, j + 1));
}
}
System.out.println();
}
// sets number of vertices in the graph
final int N = 5;
// creates a graph from edges
Graph graph = new Graph(edges, N);
boolean[] discovered = new boolean[N];
// do BFS traversal in connected components of graph
System.out.println("Detect a cycle: ");
if (BFS(graph, 1, N))
System.out.println("Graph contains cycle");
else
System.out.println("Graph doesn't contain any cycle");
}
Input: an adjacency matrix (or a prebuilt list of edges)
Current wrong output: displays some edges, but not all the edges of a cycle
Expected output: to print all the edges which create a cycle, as shown in an example above,
I would like to display: 1--2, 2--3, 3--1
The ending vertex of one edge is a starting vertex of another edge in a cycle.
I'm not claiming this is the best way to achieve the result, but it's one of the ways.
First of all, I'd change the definition of your Node:
public class Node {
int v;
Node parent;
public Node(int v, Node parent) {
this.v = v;
this.parent = parent;
}
}
Then in your method BFS, I'd change the boolean array discovered to Node array, so you know, which path leads to this Node.
// stores booleans if a vertex is discovered or not
Node[] discovered = new Node[N];
Your BFS method would work then like this:
public static boolean BFS(Graph graph, int src, int N) {
// stores booleans if a vertex is discovered or not
Node[] discovered = new Node[N];
// mark source vertex as discovered
Node start = new Node(src, null);
discovered[src] = start;
// create a queue used to do BFS and
// push source vertex into the queue
Queue<Node> q = new LinkedList<>();
q.add(start);
// run till queue is not empty
while (!q.isEmpty()) {
// pop front node from queue and print it
Node node = q.poll();
// do for every edge (v -> u)
for (int u : graph.adjList.get(node.v)) {
if (discovered[u] == null) {
// mark it as discovered
Node newNode = new Node(u, node);
discovered[u] = newNode;
// construct the queue node containing info
// about vertex and push it into the queue
q.add(newNode);
}
// u is discovered and u is not a parent
else if (u != node.parent.v) {
Node newNode = new Node(u, node);
int commonParent = findCommonParent(discovered[u], newNode);
String result = "";
Node current;
current = discovered[u];
while(current.v != commonParent) {
result = current.parent.v + "--" + current.v + ", " + result;
current = current.parent;
}
current = newNode;
while(current.v != commonParent) {
result = result + current.v + "--" + current.parent.v + ", ";
current = current.parent;
}
result = result.substring(0, result.length() - 2);
System.out.println(result);
// we found a cross-edge ie. cycle is found
return true;
}
}
}
// No cross-edges found in the graph
return false;
}
The method findCommonParent can be implemented for example like this:
private static int findCommonParent(Node n1, Node n2) {
Set<Integer> n1Parents = new HashSet<Integer>();
Node temp = n1.parent;
while(temp != null) {
n1Parents.add(temp.v);
temp = temp.parent;
}
temp = n2.parent;
while(temp != null) {
if(n1Parents.contains(temp.v)) {
break;
}
temp = temp.parent;
}
return temp.v;
}

Finding all bridge edges in an undirected graph? (Code not working)

I am learning about bridges in graphs.
I have the following C# code (also available in a fiddle - https://dotnetfiddle.net/XQEEdy):
using System;
using System.Collections.Generic;
public class Program
{
public class Graph
{
private int[,] adjMatrix;
public Graph(int vertices)
{
adjMatrix = new int[vertices, vertices];
}
public int[,] AdjMatrix
{
get
{
return adjMatrix;
}
}
public void AddEdge(int source, int destination)
{
adjMatrix[source, destination] = 1;
adjMatrix[destination, source] = 1;
}
}
public static HashSet<Tuple<int, int>> Bridges(Graph graph)
{
var visited = new HashSet<int>();
var bridges = new HashSet<Tuple<int, int>>();
var ids = new Dictionary<int, int>();
var lowLinkValues = new Dictionary<int, int>();
var parent = -1;
var id = 0;
for (int i = 0; i < graph.AdjMatrix.GetLength(0); i++)
{
if (visited.Contains(i))
{
continue;
}
Dfs(i, parent, id, bridges, ids, lowLinkValues, visited, graph.AdjMatrix);
}
return bridges;
}
private static void Dfs(
int vertex,
int parent,
int id,
HashSet<Tuple<int, int>> bridges,
Dictionary<int, int> ids,
Dictionary<int, int> lowLinkValues,
HashSet<int> visited,
int[,] adjMatrix)
{
visited.Add(vertex);
ids.Add(vertex, id);
lowLinkValues.Add(vertex, id);
id++;
for (int i = 0; i < adjMatrix.GetLength(0); i++)
{
if (parent == i)
{
continue;
}
if (!visited.Contains(i))
{
parent = vertex;
Dfs(i, parent, id, bridges, ids, lowLinkValues, visited, adjMatrix);
if (ids[vertex] < lowLinkValues[i])
{
bridges.Add(Tuple.Create(vertex, i));
}
else
{
lowLinkValues[vertex] = Math.Min(lowLinkValues[vertex], lowLinkValues[i]);
}
}
else
{
lowLinkValues[vertex] = Math.Min(lowLinkValues[vertex], ids[i]);
}
}
}
public static void Main()
{
// Adjacency Matrix:
var g = new Graph(11);
g.AddEdge(0, 1);
g.AddEdge(0, 2);
g.AddEdge(0, 3);
g.AddEdge(0, 4);
g.AddEdge(4, 2);
g.AddEdge(3, 5);
g.AddEdge(4, 6);
g.AddEdge(6, 3);
g.AddEdge(6, 7);
g.AddEdge(6, 8);
g.AddEdge(7, 9);
g.AddEdge(9, 10);
g.AddEdge(8, 10);
// bridges should be: 0--1, 3--5
// but bridges collection is empty
var bridges = Bridges(g);
foreach (var bridge in bridges)
{
Console.WriteLine(bridge.Item1);
Console.WriteLine(bridge.Item2);
Console.WriteLine("\n");
}
}
}
I have compared the code to: https://github.com/williamfiset/Algorithms/blob/master/src/main/java/com/williamfiset/algorithms/graphtheory/BridgesAdjacencyList.java
I do not see any real differences, but I am still getting nothing returned. Drawing the graph out, it looks like edge(0,1) and edge(3,5) should be bridges - as removing the edges would mean 1 & 5 would be disconnected from the graph.
Similarly, if I use the same test case from the github link I also get no bridges returned.
I am clearly missing something, but I've not been able to pick up what it might be. Does anyone see what the issue with my code is?
The problem appears to be that you've not implemented an actual depth-first search, though that appears to be your intention with the name Dfs. A depth-first search starts at some vertex and follows all edges from that vertex in a depth-first manner (follows all edges from the first child before looking at the next child).
Your algorithm, however, looks at every node and simply defines the parent as the current node, so it's not really searching, it's just looking at every node in numerical order. A simplified version of your code (in pseudocode):
Dfs(Vertex current):
mark current as visited
for each Vertex v in the graph:
if v is not visited:
Dfs(v)
Note there's no relationship between the vertex called "current" and the vertices examined from the graph. Instead, the algorithm should be more like this:
Dfs(Vertex current, Vertex parent):
mark current as visited
for each Vertex v in the graph:
if v is not visited:
if v shares an edge with current:
Dfs(v)
I'll leave it as an exercise for you to figure out how to patch your algorithm to fix this issue. There may be other issues as well. I stopped once I found the first issue.

Maximum path length between two vertices in a DAG

Given a Directed Acyclic Graph, G and two vertices u and v, I need to find the longest u-v path in G. DFS calls explore function to store visited vertices in the visited[] boolean array (if vertex is visited the value in array is set true, otherwise it's false). Vertices u and v are never marked as visited. Variable MAX stores the max path; when STOP vertex is reached in explore() function MAX is set to max of current path length and MAX value. The code doesn't work right.
import java.util.Iterator;
import java.util.LinkedList;
public class DAG2 {
int vertex;
LinkedList<Integer> list[];
int START, STOP;
int length = 0;
int MAX = 0;
public DAG2(int vertex) {
this.vertex = vertex;
list = new LinkedList[vertex];
for (int i = 0; i < vertex; i++) {
list[i] = new LinkedList<>();
}
}
public void addEdge(int source, int destination) {
// add edge
list[source].addFirst(destination);
}
void DFS(int u, int v) {
boolean[] visited = new boolean[this.vertex];
START = u;
STOP = v;
explore(v, visited);
}
private void explore(int v, boolean[] visited) {
// TODO Auto-generated method stub
visited[v] = true;
visited[START] = false;
visited[STOP] = false;
Iterator<Integer> i = list[v].listIterator();
while (i.hasNext()) {
int n = i.next();
length++;
if (n == STOP) {
MAX = Math.max(MAX, length);
length = 0;
}
if (!visited[n])
explore(n, visited);
}
}
public static void main(String args[]) {
DAG2 g = new DAG2(8);
g.addEdge(1, 2);
g.addEdge(1, 3);
g.addEdge(2, 4);
g.addEdge(2, 5);
g.addEdge(3, 6);
g.addEdge(4, 7);
g.addEdge(5, 7);
g.addEdge(6, 5);
g.addEdge(6, 7);
// new
g.addEdge(2, 3);
g.addEdge(3, 5);
g.addEdge(5, 4);
}
}
The first thing I notice about the "visited" array is that if you're looking for more than one path, you might visit a node more than once (because more than one math might lead to it, e.g. 1 -> 3 -> 4 and 1 -> 2 -> 3 -> 4 will both visit 3).
My first instinct for a depth first search is to use a recursive search. I put together one like that looks like this:
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class DAG {
private Map<Integer, List<Integer>> graph = new HashMap<>();
public void addEdge(final int src, final int dst) {
if (!graph.containsKey(src)) {
graph.put(src, new LinkedList<Integer>());
}
graph.get(src).add(dst);
}
public List<Integer> findMaxPath(final int start, final int end) {
if (start == end) {
// The path is just this element, so return a list with just the
// start (or end).
final List<Integer> path = new LinkedList<>();
path.add(start);
return path;
}
if (!graph.containsKey(start)) {
// There is no path forward.
return null;
}
List<Integer> longestPath = null;
for (Integer next : graph.get(start)) {
final List<Integer> newPath = findMaxPath(next, end);
if (null != newPath) {
// Found a new path
if ( (null == longestPath)
|| (newPath.size() > longestPath.size()) )
{
// It was longer than the previous longest,
// it is new longest.
longestPath = newPath;
}
}
}
if (null != longestPath) {
// A path was found, include this node as the start of the path.
longestPath.add(0, start);
}
return longestPath;
}
public static void main(final String[] args) {
final DAG g = new DAG();
g.addEdge(1, 2);
g.addEdge(1, 3);
g.addEdge(1, 6);
g.addEdge(2, 4);
g.addEdge(3, 5);
g.addEdge(6, 7);
g.addEdge(7, 4);
g.addEdge(2, 6);
printPath(g.findMaxPath(1, 5));
g.addEdge(4, 5); // Make a longer path.
printPath(g.findMaxPath(1, 5));
}
private static void printPath(final List<Integer> path) {
System.out.println("Path:");
if (null != path) {
for (Integer p : path) {
System.out.println(" " + p);
}
} else {
System.out.println(" null");
}
}
}
To convert it into a non-recursive method, you can use a List as a Stack. Where findMaxPath() calls itself, instead you would push() the current node on the stack and use the next one, when that's done pop() the node and continue. Put all that in a loop, and it should work.

Resources