I'm using Tarjan's Algorithm to find critical connections in an undirected graph. However when the input has 100000 vertices, it sometimes throws an TLE. I searched around and could not find out why.
I tried to implement the iterative version of Tarjan's algo but couldn't figure it out.
Is there any further improvement over the code?
Testcase Link: https://leetcode.com/submissions/detail/276043932/testcase/
import java.util.*;
class SevenSixThree {
// the order of visiting vertices
private int[] ord;
// the lowest index of the vertex that this vertex can reach
private int[] low;
// keep track of the current order;
private int count;
// result
private List<List<Integer>> result;
// graph
private Map<Integer, List<Integer>> graph;
private boolean[] visited;
public static void main(String[] args) {
SevenSixThree s = new SevenSixThree();
List<List<Integer>> list = new ArrayList<>();
List<Integer> l1 = new ArrayList<>();
l1.add(0);
l1.add(1);
list.add(new ArrayList<>(l1));
List<Integer> l2 = new ArrayList<>();
l2.add(0);
l2.add(2);
list.add(new ArrayList<>(l2));
List<Integer> l3 = new ArrayList<>();
l3.add(1);
l3.add(2);
list.add(new ArrayList<>(l3));
List<Integer> l4 = new ArrayList<>();
l4.add(1);
l4.add(3);
list.add(new ArrayList<>(l4));
List<List<Integer>> res = s.criticalConnections(4, list);
System.out.print(res.toArray().toString());
}
public List<List<Integer>> criticalConnections(int n, List<List<Integer>> connections) {
// find bridge of a graph.
// first, build the graph with map
HashMap<Integer, List<Integer>> graph = new HashMap<>();
for (int i = 0; i < n; i++) {
graph.put(i, new ArrayList<>());
}
for (List<Integer> connection : connections) {
int v = connection.get(0);
int w = connection.get(1);
graph.get(v).add(w);
graph.get(w).add(v);
}
ord = new int[n];
low = new int[n];
visited = new boolean[n];
Arrays.fill(visited, false);
result = new ArrayList<>();
dfs(0, -1, graph);
return result;
}
private void dfs(int v, int parent, HashMap<Integer, List<Integer>> graph) {
// visit this vertex
visited[v] = true;
ord[v] = count++;
low[v] = ord[v];
List<Integer> adjs = graph.get(v);
for (int w : adjs) {
if (!visited[w]) {
dfs(w, v, graph);
low[v] = Math.min(low[w], low[v]);
if (low[w] > ord[v]) {
List<Integer> bridge = new ArrayList<>();
bridge.add(v);
bridge.add(w);
result.add(bridge);
}
} else {
if (w != parent) {
low[v] = Math.min(low[v], low[w]);
}
}
}
}
Related
**can someone find the error and send the code please i am new to java
i am unable to find the error
the following are error showing
Note: PrimAlgorithmPQBetter.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details. Error: Main method
not found in class PrimAlgorithmPQBetter, please define the main
method as: public static void main(String[] args) or a JavaFX
application class must extend javafx.application.Application
import javafx.util.Pair;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.PriorityQueue;
public class PrimAlgorithmPQBetter {
static class Edge {
int source;
int destination;
int weight;
public Edge(int source, int destination, int weight) {
this.source = source;
this.destination = destination;
this.weight = weight;
}
}
static class ResultSet {
int parent;
int weight;
}
static class Graph {
int vertices;
LinkedList<Edge>[] adjacencylist;
Graph(int vertices) {
this.vertices = vertices;
adjacencylist = new LinkedList[vertices];
//initialize adjacency lists for all the vertices
for (int i = 0; i <vertices ; i++) {
adjacencylist[i] = new LinkedList<>();
}
}
public void addEgde(int source, int destination, int weight) {
Edge edge = new Edge(source, destination, weight);
adjacencylist[source].addFirst(edge);
edge = new Edge(destination, source, weight);
adjacencylist[destination].addFirst(edge); //for undirected graph
}
public void primMST(){
boolean[] mst = new boolean[vertices];
ResultSet[] resultSet = new ResultSet[vertices];
int [] key = new int[vertices]; //keys used to store the key to know whether priority queue update is required
//Initialize all the keys to infinity and
//initialize resultSet for all the vertices
for (int i = 0; i <vertices ; i++) {
key[i] = Integer.MAX_VALUE;
resultSet[i] = new ResultSet();
}
//Initialize priority queue
//override the comparator to do the sorting based keys
PriorityQueue<Pair<Integer, Integer>> pq = new PriorityQueue<>(vertices, new Comparator<Pair<Integer, Integer>>() {
#Override
public int compare(Pair<Integer, Integer> p1, Pair<Integer, Integer> p2) {
//sort using key values
int key1 = p1.getKey();
int key2 = p2.getKey();
return key1-key2;
}
});
//create the pair for for the first index, 0 key 0 index
key[0] = 0;
Pair<Integer, Integer> p0 = new Pair<>(key[0],0);
//add it to pq
pq.offer(p0);
resultSet[0] = new ResultSet();
resultSet[0].parent = -1;
//while priority queue is not empty
while(!pq.isEmpty()){
//extract the min
Pair<Integer, Integer> extractedPair = pq.poll();
//extracted vertex
int extractedVertex = extractedPair.getValue();
mst[extractedVertex] = true;
//iterate through all the adjacent vertices and update the keys
LinkedList<Edge> list = adjacencylist[extractedVertex];
for (int i = 0; i <list.size() ; i++) {
Edge edge = list.get(i);
//only if edge destination is not present in mst
if(mst[edge.destination]==false) {
int destination = edge.destination;
int newKey = edge.weight;
//check if updated key < existing key, if yes, update if
if(key[destination]>newKey) {
//add it to the priority queue
Pair<Integer, Integer> p = new Pair<>(newKey, destination);
pq.offer(p);
//update the resultSet for destination vertex
resultSet[destination].parent = extractedVertex;
resultSet[destination].weight = newKey;
//update the key[]
key[destination] = newKey;
}
}
}
}
//print mst
printMST(resultSet);
}
public void printMST(ResultSet[] resultSet){
int total_min_weight = 0;
System.out.println("Minimum Spanning Tree: ");
for (int i = 1; i <vertices ; i++) {
System.out.println("Edge: " + i + " - " + resultSet[i].parent +
" key: " + resultSet[i].weight);
total_min_weight += resultSet[i].weight;
}
System.out.println("Total minimum key: " + total_min_weight);
}
public static void main(String[] args) {
int vertices = 6;
Graph graph = new Graph(vertices);
graph.addEgde(0, 1, 4);
graph.addEgde(0, 2, 3);
graph.addEgde(1, 2, 1);
graph.addEgde(1, 3, 2);
graph.addEgde(2, 3, 4);
graph.addEgde(3, 4, 2);
graph.addEgde(4, 5, 6);
graph.primMST();
}
}
}
I have this method that prints my permutations of a Set I'm giving with my parameters. But I need to save them in 2 separate sets and compare them. So, for instance I have [5,6,3,1] and [5,6,1,3], by adding them in two separate BST, I can compare them by using the compareTo function to check whether their level order is the same. But I am having trouble with saving these permutations from my method into a set in my main. Does anyone know how to save these into a set?
What I have now:
import edu.princeton.cs.algs4.BST;
import java.util.*;
public class MyBST {
public static void main(String[] args) {
int size = 4;
BST<Integer, Integer> bst1 = new BST<Integer, Integer>();
BST<Integer, Integer> bst2 = new BST<Integer, Integer>();
Random r = new Random();
Set<Integer> tes = new LinkedHashSet<>(size);
Stack<Integer> stack = new Stack<>();
while (tes.size() < size) {
tes.add(r.nextInt(10));
}
System.out.println(tes);
System.out.println("possible combinations");
Iterator<Integer> it = tes.iterator();
for (int i = 0; i < tes.toArray().length; i++) {
Integer key = it.next();
bst1.put(key, 0);
}
combos(tes, stack, tes.size());
}
}
and here is the method I use:
public static void combos(Set<Integer> items, Stack<Integer> stack, int size) {
if (stack.size() == size) {
System.out.println(stack);
}
Integer[] itemz = items.toArray(new Integer[0]);
for (Integer i : itemz) {
stack.push(i);
items.remove(i);
combos(items, stack, size);
items.add(stack.pop());
}
}
And this is the output:
I'm not sure if I understood your idea but maybe this will help:
Yours combos method will return set of all permutations (as Stacks)
...
for (int i = 0; i < tes.toArray().length; i++) {
Integer key = it.next();
bst1.put(key, 0);
}
Set<Stack<Integer>> combos = combos(tes, stack, tes.size()); //there you have set with all Stacks
}
}
public static Set<Stack<Integer>> combos(Set<Integer> items, Stack<Integer> stack, int size) {
Set<Stack<Integer>> set = new HashSet<>();
if(stack.size() == size) {
System.out.println(stack.to);
set.add((Stack) stack.clone());
}
Integer[] itemz = items.toArray(new Integer[0]);
for(Integer i : itemz) {
stack.push(i);
items.remove(i);
set.addAll(combos(items, stack, size));
items.add(stack.pop());
}
return set;
}
Can anyone help me figure it out how to solve my problem. I need to find the shortest path between 2 given nodes. So far I have managed to save all posible paths in a list, and now I'm trying to find the minimal distance.
here is my code:
public class A {
private static int[][] adjacency = new int [6][6];
static int n = 6;
private static final int START = 1;
private static final int END = 4;
private Map<Integer, LinkedHashSet<Integer>> map = new HashMap();
private Map<Integer, List<Integer>> pathsFound = new HashMap();
public void addEdge(int node1, int node2) {
LinkedHashSet<Integer> adjacent = map.get(node1);
if(adjacent==null) {
adjacent = new LinkedHashSet();
map.put(node1, adjacent);
}
adjacent.add(node2);
}
public LinkedList<Integer> adjacentNodes(Integer last) {
LinkedHashSet<Integer> adjacent = map.get(last);
if(adjacent==null) {
return new LinkedList();
}
return new LinkedList<Integer>(adjacent);
}
public static void main(String[] args) {
LinkedList<Integer> visited = new LinkedList<Integer>();
visited.add(START);
A graph = new A();
for (int i=0;i<n;i++)
for (int j=0;j<n;j++)
adjacency[i][j] = 0;
adjacency[0][1] = 1;
adjacency[0][2] = 2;
adjacency[1][0] = 1;
adjacency[1][3] = 5;
adjacency[1][4] = 9;
adjacency[1][5] = 6;
adjacency[2][0] = 2;
adjacency[2][4] = 7;
adjacency[2][5] = 2;
adjacency[3][1] = 5;
adjacency[4][1] = 9;
adjacency[4][2] = 7;
adjacency[4][5] = 1;
adjacency[5][1] = 6;
adjacency[5][2] = 2;
adjacency[5][4] = 1;
graph.addEdge(0,1);
graph.addEdge(0,2);
graph.addEdge(1,0);
graph.addEdge(1,3);
graph.addEdge(1,4);
graph.addEdge(1,5);
graph.addEdge(2,0);
graph.addEdge(2,4);
graph.addEdge(2,5);
graph.addEdge(3,1);
graph.addEdge(4,1);
graph.addEdge(4,2);
graph.addEdge(4,5);
graph.addEdge(5,1);
graph.addEdge(5,2);
graph.addEdge(5,4);
graph.breadthFirst(visited);
}
public void breadthFirst(LinkedList<Integer> visited) {
LinkedList<Integer> nodes = adjacentNodes(visited.getLast());
List<List<Integer>> allPaths = new ArrayList<List<Integer>>();
List<Integer> distances = new ArrayList<Integer>();
for (int node : nodes) {
if (visited.contains(node))
continue;
if (node == END) {
visited.add(node);
List<Integer> path = getPath(visited);
System.out.println(path);
??allPaths.add(path);
visited.removeLast();
break;
}
}
for (int node : nodes) {
if (visited.contains(node) || node == END)
continue;
visited.addLast(node);
breadthFirst(visited);
visited.removeLast();
}
System.out.println(allPaths.get(0));
}
public static List<Integer> getPath(LinkedList<Integer> visited) {
List<Integer> path = new ArrayList<Integer>();
for (int node : visited)
path.add(node);
return path;
}
}
If I do like this System.out.println(path); it prints the path, which means that the function getPath() works.
But when I want to put this path in a list : allPaths.add(path); something goes wrong, because when I call after the for loop end System.out.println(allPaths.get(0)); I get an IndexOutOfBoundException. I really don't understand why my allPaths list is empty...
Why don't you iterate with a foreach ?
for (int number : arrlist) {
System.out.println("Number = " + number);
}
Are you perhaps invoking the last snippet (in your question) before you have filled in the distances collection? You need to invoke it afterwards, not before.
[Aside: In the future, if you have an exception, you really need to provide the exception message and stack trace. Makes helping you much easier...]
I want to read data from a file and construct a graph from it. I did everything, all vertices are created normally, but when I add them to the graph, their adjacent lists (which are maps, whose key value is adjacent vertex's number, and value is their distance) become empty. Can anyone, please, tell what's the problem with my code?
public class Vertex {
private int number;
private LinkedHashMap<Integer, Integer> adjacent;
public Vertex(int num) {
this.number = num;
this.adjacent = new LinkedHashMap<Integer, Integer>();
}
}
public class Graph {
private ArrayList<Vertex> vertices;
private int verticesSize = 201;
public Graph() {
Vertex initialVertex = new Vertex(0);
this.vertices = new ArrayList<Vertex>();
for(int i = 0; i < verticesSize; i++) {
vertices.add(i, initialVertex);
}
}
}
public class Test {
public static void printGraph(Graph graph) {
for(int i = 0; i < graph.getVerticesSize(); i++)
System.out.println(graph.getVertices().get(i));
}
public static void main(String[] args) throws IOException {
FileInputStream fStream = new FileInputStream("C:/Lusine/Programming/Java/dijkstraData.txt");
// Use DataInputStream to read binary NOT text.
BufferedReader bReader = new BufferedReader(new InputStreamReader(fStream));
Graph graph = new Graph();
String[] maps;
String line;
LinkedHashMap<Integer, Integer> currentMap = new LinkedHashMap<Integer, Integer>();
while( (line = bReader.readLine()) != null) {
maps = line.split("\t");
int firstDigit = Integer.parseInt(maps[0]);
Vertex v = new Vertex(firstDigit);
for(int i = 1; i < maps.length; i++) {
String[] vertexDistance = maps[i].split(",");
int vertex = Integer.parseInt(vertexDistance[0]);
int distance = Integer.parseInt(vertexDistance[1]);
currentMap.put(vertex, distance);
}
v.setAdjacent(currentMap);
graph.getVertices().set(firstDigit, v);
System.out.println("\n" + firstDigit +"-th vertex is\n" + v);
currentMap.clear();
}
printGraph(graph);
}
when I print v, it's ok, but when I print graph, all adjacent lists are empty. What's the problem?
Your loop boils down to
LinkedHashMap<Integer, Integer> currentMap = new LinkedHashMap<Integer, Integer>();
while ( ... ) {
Vertex v = new Vertex(...);
v.setAdjacent(currentMap);
currentMap.clear();
}
So, you're storing the same map of adjacent vertices in every vertex, and you clear this map at the end of each iteration. So obviously, all the vertices share the same, empty map, at the end of the loop.
You should create a new LinkedHashMap at every iteration:
while ( ... ) {
LinkedHashMap<Integer, Integer> currentMap = new LinkedHashMap<Integer, Integer>();
Vertex v = new Vertex(...);
v.setAdjacent(currentMap);
}
And you should not clear it, cince clearing it, well... clears it.
Good morning!
I'm developing an algorithm to find all the paths in an undirected, not weighted graph. I'm currently using a DFS algortihm with backtracking to try and do that. Here is my current code:
import java.util.*;
public class dfs {
private static Map<Integer, LinkedHashSet<Integer>> map = new HashMap<Integer, LinkedHashSet<Integer>>();
private int startNode;
private int numLinks;
public dfs(int startNode, int numLinks) {
super();
this.startNode = startNode;
this.numLinks = numLinks;
}
public void addEdge(int source, int destiny) {
LinkedHashSet<Integer> adjacente = map.get(source);
if(adjacente==null) {
adjacente = new LinkedHashSet<Integer>();
map.put(source, adjacente);
}
adjacente.add(destiny);
}
public void addLink(int source, int destiny) {
addEdge(source, destiny);
addEdge(destiny, source);
}
public LinkedList<Integer> adjacentNodes(int last) {
LinkedHashSet<Integer> adjacente = map.get(last);
System.out.println("adjacentes:" + adjacente);
if(adjacente==null) {
return new LinkedList<Integer>();
}
return new LinkedList<Integer>(adjacente);
}
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int numVertices = input.nextInt();
int numLinks = input.nextInt();
int startNode = input.nextInt();
int endNode = startNode;
dfs mapa = new dfs(startNode, numLinks);
for(int i = 0; i<numLinks; i++){
mapa.addLink(input.nextInt(), input.nextInt());
}
List<ArrayList<Integer>> paths = new ArrayList<ArrayList<Integer>>();
List<Integer> visited = new ArrayList<Integer>();
visited.add(startNode);
Integer currentNode = 0;
Iterator it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pairs = (Map.Entry)it.next();
currentNode = (Integer) pairs.getKey();
//System.out.println("Current Node:" + currentNode);
mapa.findAllPaths(mapa, visited, paths, currentNode);
}
}
private void findAllPaths(dfs mapa, List<Integer> visited,
List<ArrayList<Integer>> paths, Integer currentNode) {
if (currentNode.equals(startNode)) {
paths.add(new ArrayList<Integer>(visited));
LinkedList<Integer> nodes = mapa.adjacentNodes(currentNode);
//System.out.println("visited:" + visited);
for (Integer node : nodes) {
//System.out.println("nodes:" + nodes);
List<Integer> temp = new ArrayList<Integer>();
temp.addAll(visited);
temp.add(node);
findAllPaths(mapa, temp, paths, node);
}
}
else {
LinkedList<Integer> nodes = mapa.adjacentNodes(currentNode);
System.out.println("currentNode:" + currentNode);
//System.out.println("nodes:" + nodes);
for (Integer node : nodes) {
if (visited.contains(node)) {
continue;
}
List<Integer> temp = new ArrayList<Integer>();
temp.addAll(visited);
System.out.println("visited:" + visited);
temp.add(node);
findAllPaths(mapa, temp, paths, node);
}
}
}
}
The program receives integers on his input. The first one is the number of nodes, the second one is the number of links and the third is the start node and end note, which are the same. All the integers that come after represent the connections between nodes.
The problem is, this algorithm is finding all the paths that visit a single node only once. What i want is the algorithm to find all the paths that visit each connection only once.
Any idea on how i can do that?
You are on the right track - backtracking is a neat way to solve it.
To get all paths that "uses the same edge only once":
after you use an edge in findAllPaths() - delete it from the set of edges [delete the connection from the LinkedHashSet of each vertex of this edge] - and invoke recursively.
After you return from the recursion - don't forget to "clean up the environment" and add this edge back to both vertices.
You will need to make sure you don't run into troubles of iterating collection while modifying it. [You cannot do it - the result of doing so is unexpected] - so you will probably need to send a copy of the LinkedHashSets [without the relevant edge] - and not the original one.