Find a path algorithm in a graph using java - java

I have to implement a search algorithm in java for a school project. In this algorithm i need to find, in an undirected graph, a path that goes through each link only once and ends in the start node. I'm trying to use a DFS with backtracking to solve this problem, but i'm having trouble implementating it. Here's my code:
import java.util.*;
public class Graph {
private Map<Integer, LinkedHashSet<Integer>> map =
new HashMap<Integer, LinkedHashSet<Integer>>();
private int startNode;
private int numLinks;
public Graph(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;
Graph mapa = new Graph(startNode, numLinks);
for(int i = 0; i<numLinks; i++){
mapa.addLink(input.nextInt(), input.nextInt());
}
List<ArrayList<Integer>> paths = new ArrayList<ArrayList<Integer>>();
Integer currentNode = startNode;
List<Integer> visited = new ArrayList<Integer>();
visited.add(startNode);
mapa.findAllPaths(mapa, visited, paths, currentNode);
for(ArrayList<Integer> path : paths){
for (Integer node : path) {
System.out.print(node);
System.out.print(" ");
}
System.out.println();
}
}
private void findAllPaths(Graph mapa, List<Integer> visited,
List<ArrayList<Integer>> paths, Integer currentNode) {
if (currentNode.equals(startNode)) {
paths.add(new ArrayList<Integer>(visited));
return;
}
else {
LinkedList<Integer> nodes = mapa.adjacentNodes(currentNode);
for (Integer node : nodes) {
if (visited.contains(node)) {
continue;
}
List<Integer> temp = new ArrayList<Integer>();
temp.addAll(visited);
temp.add(node);
findAllPaths(mapa, temp, paths, node);
}
}
}
}
The program is supposed to receive integers on his input, where the first one is the number of nodes, the second one is the number of links, the third is the start node(wich is also the end node), all the integers that come after represent the links between nodes.
The goal is to, in the end, print a single line with integers. This integers represent the order i visit each node to complete the path. Currently testing, it only prints a single integer, wich represents the first node.
I think my problem is either populating the graph, populating the adjacent list. Can somebody help me?

The problem is that when you call mapa.findAllPaths(mapa, visited, paths, currentNode);, you don't actually find all paths. You only find one path (i.e. the current node) and you return:
private void findAllPaths(Graph mapa, List<Integer> visited,
List<ArrayList<Integer>> paths, Integer currentNode) {
if (currentNode.equals(startNode)) {
paths.add(new ArrayList<Integer>(visited));
return;// <--- WRONG!!!
} else {
// The else is never executed!
}
}
You should either have a loop or recursively call the findAllPaths until you find all the paths.

The first time you invoke the findAllPaths method you are passing the startNode as the last argument (the currentNode), which leads to currentNode.equals(startNode) being true and as such the only part of the method that gets executed is:
paths.add(new ArrayList<Integer>(visited));
return;
In essence, you only add the first node to your paths and then your algorithm finishes, thus always printing a single integer, the start node.

Related

From BST (binary search tree) to linkedlist array

A binary search tree was created by traversing through an array from left to right and inserting each element. This tree may not be a balanced tree. Given a binary search tree with distinct elements, print all possible arrays that could have led to this tree.
To answer to this question I wrote the following code. Still, it seems that it doesn't print all possible arrays that could have lead to the the tree in all the cases. What do you think should be modified ?
public class Main {
public static LinkedList<Integer> passed = new LinkedList<>();
public static LinkedList<BinaryTree> notyet = new LinkedList<>();
public static ArrayList<LinkedList<Integer>> results = new ArrayList<LinkedList<Integer>>();
public static void main(String args[]) {
BinaryTree tr = readTree();
ArrayList<LinkedList<Integer>> result = allSequences(tr);
for (LinkedList<Integer> l : result){
for(int elem: l) System.out.print(elem+" ");
System.out.println("");
}
}
private static BinaryTree readTree() {
BinaryTree tr = new BinaryTree(2, null, null);
tr.left = new BinaryTree(1, null, null);
tr.right = new BinaryTree(3, null, null);
return tr;
}
public static ArrayList<LinkedList<Integer>> allSequences(BinaryTree tr){
// implement here
ArrayList<LinkedList<Integer>> result = new ArrayList<LinkedList<Integer>>();
findseqs(passed,notyet,tr);
//result=results.clone();
for(LinkedList<Integer> sample :results){
result.add(sample);
}
return result;
}
public static void findseqs(LinkedList<Integer> passed, LinkedList<BinaryTree> notyet, BinaryTree tr) {
passed.add(tr.value);
if (tr.left != null) notyet.add(tr.left);
if (tr.right != null) notyet.add(tr.right);
if (notyet.isEmpty()) {
results.add(passed);
}
for (BinaryTree elem: notyet) {
LinkedList<Integer> temp = (LinkedList<Integer>) passed.clone();
LinkedList<BinaryTree> ptemp = (LinkedList<BinaryTree>) notyet.clone();
ptemp.remove(elem);
findseqs(temp, ptemp, elem);
}
}
What holds about the array is that if A is ancestor of B in the graph then A precedes B in the array. Nothing else can be assumed.
So the arrays can be produced by the following recursive function.
function sourceArrays(Tree t)
// leafe node
if t == null
return empty list;
r = root(t);
append r to existing arrays;
la = sourceArrays(t.left);
ra = sourceArrays(t.right);
ac = createArrayCombitations(la, ra);
append ac to existing arrays;
end
function createArrayCombitations(la, ra)
foreach a in la
foreach b in ra
r = combineArrays(a,b);
add r to result;
end
end
end
function combineArrays(a, b)
generate all combinations of elements from two array such that order of elements in each array is preserved.
Ie if x precedes y in a or b the x precedes y in result

Issue passing argument to my main using DFS - Java

I am trying to get this code running as fast as possible when traversing through my stack of my DFS currently the input files are like so:
0 2
2 1
1 4
4 5
5 6
10 8
8 9
9 6
7 6
3 4
0 1
3 9
0 4
Where my Maze class will tie the numbers together and create a graph for me. After the graph is created my DFS class runs through traversing giving one or all solutions to the .txt file submitted.I have recently altered my Maze class as for it to run more efficiently but am being thrown errors and the data is parsing through to my DFS to be outputted. My Maze class is as follows:
import java.io.*;
import java.util.*;
public class Maze {
private final Map<Integer, Set<Integer>> adjList = new HashMap<>();
/**
* The main constructor that takes a String for reading maze file.
*
* #param file
*/
public Maze(File file) throws FileNotFoundException {
try (Scanner scan = new Scanner(file)) {
while (scan.hasNextInt()) {
int node1 = scan.nextInt();
int node2 = scan.nextInt();
this.connect(node1, node2);
this.connect(node2, node1);
}
}
}
/**
* Makes a unidirectional connection from node1 to node2.
*/
private void connect(int node1, int node2) {
if (!this.adjList.containsKey(node1)) {
this.adjList.put(node1, new HashSet<Integer>());
}
this.adjList.get(node1).add(node2);
}
/**
* Returns a human-readable description of the adjacency lists.
*/
public String toString() {
StringBuilder s = new StringBuilder();
for (Map.Entry<Integer, Set<Integer>> adj : this.adjList.entrySet()) {
int from = adj.getKey();
Set<Integer> to = adj.getValue();
s.append(from).append(" connected to ").append(to).append('\n');
}
return s.toString();
}
/**
* Returns the set of nodes connected to a particular node.
*
* #param node - the node whose neighbors should be fetched
*/
public Iterable<Integer> getadjList(int node) {
return Collections.unmodifiableSet(adjList.get(node));
}
/**
* Demonstration of file reading.
*/
public static void main(String[] args) throws FileNotFoundException {
System.err.print("Enter File: ");
Scanner scanFile = new Scanner(System.in);
String file = scanFile.nextLine();
Maze m = new Maze(new File(file));
System.out.println(m);
}
}
And my DFS looks like so.
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
import java.util.Stack;
public class DFS {
//starting node, the route to the next node, has node been visited
private int startNode;
private int[] route;
private boolean[] visited;
// 2 main arguments - Maze File & user input
public DFS(Maze maze, int inputInt) {
int startNode = 0;
int goalNode = 1;
route = new int[maze.node];
visited = new boolean[maze.node];
//Takes user's input and runs desired function
if(inputInt == 1){
findOne(maze, startNode, goalNode);
}
else if (inputInt == 2){
findAll(maze, startNode, goalNode);
}
else {
System.out.println("input invalid. No Solution Returned");
}
}
//Put path to goal in the stack
public Stack<Integer> route(int toGoalNode) {
if (!visited[toGoalNode]) {
return null;
}
Stack<Integer> pathStack = new Stack<Integer>();
for (int routeGoalNode = toGoalNode; routeGoalNode != startNode; routeGoalNode = route[routeGoalNode]) {
pathStack.push(routeGoalNode);
}
pathStack.push(startNode);
reverseStack(pathStack);
return pathStack;
}
//Reverse the stack
public void reverseStack(Stack<Integer> stackToBeReverse) {
if (stackToBeReverse.isEmpty()) {
return;
}
int bottom = popBottomStack(stackToBeReverse);
reverseStack(stackToBeReverse);
stackToBeReverse.push(bottom);
}
//Pop the bottom of the stack
private int popBottomStack(Stack<Integer> stackToBeReverse) {
int popTopStack = stackToBeReverse.pop();
if (stackToBeReverse.isEmpty()) {
return popTopStack;
} else {
int bottomStack = popBottomStack(stackToBeReverse);
stackToBeReverse.push(popTopStack);
return bottomStack;
}
}
//performs DFS and unsets visited to give the result of all paths
private void findAll(Maze maze, int node, int goal) {
visited[node] = true;
if(node == goal) {
printPath(goal);
} else {
for (int con : maze.getadjList(node)) {
if (!visited[con]) {
route[con] = node;
findAll(maze, con, goal);
}
}
}
visited[node] = false;
}
//performs DFS and maintains visited marker giving only one path
private void findOne(Maze maze, int node, int goal) {
visited[node] = true;
for (int con : maze.getadjList(node)) {
if (!visited[con]) {
route[con] = node;
findOne(maze, con, goal);
}
}
}
//Traverse the connections to the goal and print the path taken
public void printPath( int toGoal) {
int goalNode = 1;
if (visited[toGoal]) {
System.out.println("Completed Path: ");
for (int t : route(toGoal)) {
if (t == toGoal) {
System.out.print(t);
} else {
System.out.print(t + " -> ");
}
}
System.out.println();
}
}
public static void main(String[] args) throws FileNotFoundException {
Scanner scanFile = new Scanner(System.in);
int goalNode = 1;
System.out.print("Enter maze file: ");
String file = scanFile.nextLine();
Maze maze = new Maze(new File(file));
Scanner scanInt = new Scanner(System.in);
System.out.print("Enter desired feedback (1 = one soultion, 2 = all): ");
int inputInt = scanInt.nextInt();
// maze.toString();
System.out.println(maze);
DFS dfs = new DFS(maze, inputInt);
dfs.printPath(goalNode);
}
}
I've been looking over it for a while and can't figure out exactly why the data is parsing and being used. Ive altered a few things here and there but have been thrown even more errors. They specifically say
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
at DFS.findOne(DFS.java:90)
at DFS.<init>(DFS.java:22)
at DFS.main(DFS.java:127)
Referencing to the lines of code:
visited[node] = true;
findOne(maze, startNode, goalNode);
DFS dfs = new DFS(maze, inputInt);
Now essentially im lead to believe that there is no argument being passed, if someone could pin point the problem and lend a hand in helping me out it would be greatly appreciated. Thanks again
EDIT:: Old version of Maze class
import java.io.*;
import java.util.*;
public class Maze {
static Set<Integer> Nodes = new HashSet<Integer>();
List<Integer>[] conList;
int node; //declaring value for my nodes.
int con; // declaring a connection
//Constructor takes an int parameter to read through the list of corresponding nodes
Maze(int node) {
this.node = node;
this.con = 0;
conList = (List<Integer>[]) new List[node];
for (int index = 0; index < node; index++) {
conList[index] = new LinkedList<Integer>();
}
}
//Constructor that takes a String of the maze file
public Maze(String mazeFile) {
this(nodeSize(mazeFile));
Scanner scan;
try {
//Creates a scanner for reading the file and loops through linking the nodes to their connections.
scan = new Scanner(new File(mazeFile));
while (scan.hasNextInt()) {
int firstNode = scan.nextInt();
int secondNode = scan.nextInt();
addCon(firstNode, secondNode);
}
} catch (FileNotFoundException ex) {
System.out.println("File Not Found.");
}
}
/*Takes String parameter which is the name of the maze file.
* Method designed to return the the size of the set of nodes
*/
public static int nodeSize(String mazeFile) {
Scanner scanNodeSize;
try {
scanNodeSize = new Scanner(new File(mazeFile));
//while scan has more int's left repeat.
while (scanNodeSize.hasNextInt()) {
int firstNode = scanNodeSize.nextInt();
int secondNode = scanNodeSize.nextInt();
Nodes.add(firstNode);
Nodes.add(secondNode);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return Nodes.size();
}
//Method designed to connect the first and second nodes
private void addCon(int firstNode, int secondNode) {
con++;
conList[firstNode].add(secondNode);
conList[secondNode].add(firstNode);
}
//outputs the nodes and their connection's (#remove later?)
public void print() {
for (int n = 0; n < node; n++) {
System.out.print(n + " connected to ");
for (int w : conList[n]) {
System.out.print(w + " ");
}
System.out.println();
}
}
//method returns a list, enabling nodes to be easily accessible.
public Iterable<Integer> getconList(int nodes) {
return conList[nodes];
}
}
You are getting an index out of bounds exception at 0. This should lead you to believe that the array has not properly been initialized. You initialize the visited[] array with maze.node however nowhere in your code do we see where this node variable is located. You need to give a proper value to maze.node if you want this to even be runnable.
*EDIT - My above answer is no longer applicable now that we have your previous Maze class which explains why the code will not run.
There are so many things wrong with the code in its current state so I will try and give you some direction here:
Your new way of creating a Maze is to read from the file and connect the 2 points and store them in an Map. The issue with this is that you cannot just get the next element since you have to have the key to get the element. To fix this you should use a different data structure.
public DFS(Maze maze, int inputInt) {
int startNode = 0;
int goalNode = 1;
route = new int[maze.node]; //!!! maze.node isn't a thing anymore
visited = new boolean[maze.node]; //!!! maze.node isn't a thing anymore
You can see that you are trying to access maze.node which use to be a variable of Maze. It no longer is. You need to find a new way of getting a node from Maze. To do this you need to grab the node from your data structure in a different way:
public DFS(Maze maze, int inputInt) {
int startNode = 0;
int goalNode = 1;
route = new int[maze.adjList.getNode()];
visited = new boolean[maze.adjList.getNode()];
You have a lot of options for a different data structure for you adjacency list but something such as this:
http://theoryofprogramming.com/adjacency-list-in-java/
will give you a decent starting point.

Build graph given coordinates of adjacent nodes

The way you can interpret this is as such:
nodeName
nodeName's x-coord, nodeName's y-coord
x-coord of an adjacent node, y-coord of that adjacent node
...and the rest are just more coordinates of adjacent nodes. I'm trying to figure out how to store this as a graph so I can check if a path is legal. For example, maybe nodeA-nodeB-nodeC is legal, but nodeA-nodeC-nodeD is not.
So, my final question is: what is the best way to code the Graph class, and populate it by reading in this data?
You can split file to groups of lines. Each group describes node. And then parse all groups.
Map<Node, List<Node>> neighbors;
Map<String, Node> nodeByCoords;
// Get node by it's coordinates. Create new node, if it doesn't exist.
Node getNode(String coords) {
String[] crds = coords.split(" ");
int x = Integer.parseInt(crds[0]);
int y = Integer.parseInt(crds[1]);
String key = x + " " + y;
if (!nodeByCoords.containsKey(key)) {
Node node = new Node();
node.setX(x);
node.setY(y);
nodeByCoords.put(key, node);
neighbords.put(node, new ArrayList<Node>());
}
return nodeByCoords.get(key);
}
// Create node (if not exists) and add neighbors.
void List<String> readNode(List<String> description) {
Node node = getNode(description.get(1));
node.setName(description.get(0));
for (int i = 2; i < description.size(); i++) {
Node neighbor = getNode(description.get(i));
neighbors.get(node).add(neighbor);
}
}
// Splits lines to groups. Each group describes particular node.
List<List<String>> splitLinesByGroups (String filename) {
BufferedReader reader = new BufferedReader(new FileReader(filename));
List<List<String>> groups = new ArrayList<List<String>>();
List<String> group = new ArrayList<String>();
while (reader.ready()) {
String line = reader.readLine();
if (Character.isLetter(line.charAt())) {
groups.add(group);
group = new ArrayList<String>();
}
group.add(line);
}
groups.add(group);
return groups;
}
// Read file, split it to groups and read nodes from groups.
void readGraph(String filename) {
List<List<String>> groups = splitLineByGroups(filename);
for (List<String> group: groups) {
readNode(group);
}
}
I think there is no need to store nodes somehow to find out whether the path is legal: you can check the legalty of the next node when reading them. The next node is legal if and only if it's coordinates differ to previous ones by no more than 1.
You might want to consider using JGraphT
You could just create an instance of the SimpleGraph and populate it with nodes and edges:
// Define your node, override 'equals' and 'hashCode'
public class Node {
public int x, y;
Node (int _x, int _y) {
x = _x;
y = _y;
}
#Override public boolean equals (Object other) {
if ( (other.x == x)
&& (other.y == y))
return true;
return false;
}
/* Override hashCode also */
}
// Later on, you just add edges and vertices to your graph
SimpleGraph<Node,Edge> sg;
sg.addEdge (...);
sg.addVertex (...);
Finally, you can use DijkstraShortestPath to find whether or not a path exists:

Search algorithm (graph) in a single java file

I have to implement a search algorithm for a school assignment. Right now, i'm having problems with sole java implementation. Here's the code i have at the moment (i have been basing myself in some code i found here in stackoverflow for the dfs search, then i have to add verifications to meet the project criteria):
import java.util.*;
public class dfs<Grafo> {
public static void main(String[] args) {
class Grafo{
private Map<Integer, LinkedHashSet<Integer>> map = new HashMap();
public void addEdge(int source, int destiny) {
LinkedHashSet<Integer> adjacente = map.get(source);
if(adjacente==null) {
adjacente = new LinkedHashSet();
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);
if(adjacente==null) {
return new LinkedList();
}
return new LinkedList<Integer>(adjacente);
}
}
Scanner input = new Scanner(System.in);
int numVertices = input.nextInt();
int numLinks = input.nextInt();
int startNode = input.nextInt();
int endNode = startNode;
Grafo mapa = new Grafo();
for(int i = 0; i<numLinks; i++){
mapa.addLink(input.nextInt(), input.nextInt());
}
List<ArrayList<Integer>> paths = new ArrayList<ArrayList<Integer>>();
Integer currentNode = startNode;
List<Integer> visited = new ArrayList<Integer>();
visited.add(startNode);
new dfs().findAllPaths(mapa, visited, paths, currentNode);
for(ArrayList<Integer> path : paths){
for (Integer node : path) {
System.out.print(node);
System.out.print(" ");
}
System.out.println();
}
}
private void findAllPaths(Grafo mapa, List<Integer> visited,
List<ArrayList<Integer>> paths, Integer currentNode) {
if (currentNode.equals(startNode)) {
paths.add(new ArrayList(Arrays.asList(visited.toArray())));
return;
}
else {
LinkedList<Integer> nodes = mapa.adjacentNodes(currentNode);
for (Integer node : nodes) {
if (visited.contains(node)) {
continue;
}
List<Integer> temp = new ArrayList<Integer>();
temp.addAll(visited);
temp.add(node);
findAllPaths(mapa, temp, paths, node);
}
}
}
}
The problem i have with this, is that i can only turn in a single java file, so i'm putting everything in this single file.
When i get to the findAllPaths function he does not recognise the "startNode" constant (eclipse says that it cannot be be resolved to a variable) and he says "adjacentNodes" function is not defined for the type Grafo.
Is there anyway i can solve this problem or do i have to rethink the way i'm doing this, if so, what's a good way to implement this?
Others seem to have addressed some of your coding issues, so I just wanted to illustrate how to work with the single file constraint.
Suppose you had 3 classes, Edge, Node, and Graph that you developed in three separate files. Here's how you could combine them:
// in file GraphSearchHomework.java
public class GraphSearchHomework {
public static class Edge {
// ... Edge code here ...
// You can reference Nodes and Graphs
// just as if this was in a separate file
}
public static class Node {
// ... Node code here ...
// You can reference Edges and Graphs
// just as if this was in a separate file
}
public static class Graph {
// ... Graph code here ...
// You can reference Edges and Nodes
// just as if this was in a separate file
}
public static void main(String args[]) {
// This main can instantiate Graphs, Nodes, Edges
// Keep this simple, though. Most code belongs outside of main.
}
}
You seem to have made some mistakes trying to force this into one file. If it helps you, go ahead and develop each class separately and then combine them.
I cleaned out your errors and warnings for you.
Still doesn't run well, but you can sort that out on your own..
Looks like you don't need the outer class dts. If you make the Grafo your top level class it becomes much cleaner.
If you make the startNode a class variable you can instantiate it in your main method and you can access it in your other methods.
Also when you instantiate generic classes you should specify the generic type like this:
new LinkedList<Integer>();
I wouldn't hand it in just yet, but at least the structure is a bit cleaner..
import java.util.*;
public class Grafo {
private Map<Integer, LinkedHashSet<Integer>> map = new HashMap<Integer, LinkedHashSet<Integer>>();
private int startNode;
public Grafo(int startNode) {
super();
this.startNode = startNode;
}
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);
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;
Grafo mapa = new Grafo(startNode);
for(int i = 0; i<numLinks; i++){
mapa.addLink(input.nextInt(), input.nextInt());
}
List<ArrayList<Integer>> paths = new ArrayList<ArrayList<Integer>>();
Integer currentNode = startNode;
List<Integer> visited = new ArrayList<Integer>();
visited.add(startNode);
mapa.findAllPaths(mapa, visited, paths, currentNode);
for(ArrayList<Integer> path : paths){
for (Integer node : path) {
System.out.print(node);
System.out.print(" ");
}
System.out.println();
}
}
private void findAllPaths(Grafo mapa, List<Integer> visited,
List<ArrayList<Integer>> paths, Integer currentNode) {
if (currentNode.equals(startNode)) {
paths.add(new ArrayList<Integer>(visited));
return;
}
else {
LinkedList<Integer> nodes = mapa.adjacentNodes(currentNode);
for (Integer node : nodes) {
if (visited.contains(node)) {
continue;
}
List<Integer> temp = new ArrayList<Integer>();
temp.addAll(visited);
temp.add(node);
findAllPaths(mapa, temp, paths, node);
}
}
}
}
startNode is a local variable in main(), and thus is not recognized by findAllPaths() [remember, one might invoke this from a method which is not main...] java has static binding so it forbids this.
You can add it as a parameter to findAllPaths(), or you can make startNode a field in your class dfs, and then findAllPaths() will be able to access it.
Same idea for Grafo - you declared it as a method inner class, you should declare it as an inner class for the class - otherwise only main() will "know" how to use it.

Find all paths in a graph with DFS

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.

Categories

Resources