I have implemented a directed graph in java, using Map data structure.
Currently, I have two Map data structures:
Holds each Node, with All in-degree vertices.
Holds each Node, with All out-degree vertices.
My problem is as follows:
I would like to implement a shortest path algorithm that, given a specific node and a secondary node, finds the shortest path between the first node to the second node.
I am not sure how to implement it using Map data structure.
public class NetworkInfluence {
private int numEdges; //number of edges
private int numVert; //number of vertices
private int numIter; //number of page rank iterations
private Map<String, List<String>> AtoB; //out degree of vertices
private Map<String, List<String>> BtoA; //in degree of vertices
private Map<String, Double> influenceMap; //page ranks of vertices
private Set<String> nodeCounter; //list of vertices
/**
* Creates a new PageRank object. This is used to find the pagerank
* of a graph represented as an edgelist in a text file.
* #param fileName Name of text file containing graph edge list.
* #param eps Convergence parameter for pagerank.
* #throws FileNotFoundException If text file containing graph cannot be found.
* #throws IOException If error reading a text file.
*/
public NetworkInfluence(String fileName) throws FileNotFoundException, IOException {
numIter = 0;
numEdges = 0;
AtoB = new HashMap<String, List<String>>();
BtoA = new HashMap<String, List<String>>();
Set<String> nodeCounter = new HashSet<String>();
FileReader fr = new FileReader(fileName);
BufferedReader b = new BufferedReader(fr);
String line = b.readLine();
String nodes[];
List<String> toList;
List<String> fromList;
while((line = b.readLine()) != null) {
numEdges++;
nodes = line.toLowerCase().split(" ");
//A->B
if(!AtoB.containsKey(nodes[0])) {
toList = new ArrayList<String>();
toList.add(nodes[1]);
AtoB.put(nodes[0], toList);
} else {
toList = AtoB.get(nodes[0]);
toList.add(nodes[1]);
AtoB.put(nodes[0], toList);
}
//B->A
if(!BtoA.containsKey(nodes[1])) {
fromList = new ArrayList<String>();
fromList.add(nodes[0]);
BtoA.put(nodes[1], fromList);
} else {
fromList = BtoA.get(nodes[1]);
fromList.add(nodes[0]);
BtoA.put(nodes[1], fromList);
}
nodeCounter.add(nodes[0]);
nodeCounter.add(nodes[1]);
}
this.nodeCounter = nodeCounter;
numVert = nodeCounter.size();
b.close();
Any help would be appreciated. Thanks.
As mentioned you can solve it with dijkstra even if you are using hashmaps. In addition to your structure you have to somehow the costs of edges, something like this:
Map<String, Map<String, Integer>> costs = new HashMap<>();
...
// where the cost of edge ("node0", "node1") is:
int cost = costs.get("node0").get("node1");
the part od dijkstra may be something like this (i did not care about optimizing map access):
public List<String> path(String node0, String node1) {
// array to keep trace of visited nodes
Map<String, Boolean> visited = new HashMap<>();
// array to keep trace of predecessors of nodes in the path
Map<String, String> pred = new HashMap<>();
// initialize maps
for (String n : nodeCounter) {
visited.put(n, false);
pred.put(n, node0);
}
// min costs from node0 to any other node, initialized to INFINITE if
// the nodes are not adjacent
Map<String, Integer> mincosts = new HashMap<>();
for (String n : nodeCounter)
mincosts.put(n, costs.get(node0).get(n));
// initialize flags of start node
visited.put(node0, true);
mincosts.put(node0, 0);
// iterate until all vertexes or node1 are reached
for (int i = 0; (i < numVert) && (!visited.get(node1)); ++i) {
int min = inf;
String candidate = null;
for (String n : nodeCounter)
if (!visited.get(n) && mincosts.get(n) < min) {
min = mincosts.get(n);
candidate = n;
}
if (candidate == null)
break;
visited.put(candidate, true);
for (String n : nodeCounter)
if (!visited.get(n) && ((mincosts.get(candidate) + costs.get(candidate).get(n)) < mincosts.get(n))) {
mincosts.put(n, mincosts.get(candidate) + costs.get(candidate).get(n));
pred.put(n, candidate);
}
}
if (!visited.get(node1))
return null;
// store the path from node1 to node0, using predecessors
// map
String current = node1;
List<String> path = new ArrayList<>();
path.add(current);
while (!current.equals(node0))
path.add(current = pred.get(current));
// store the path from node0 to node1
Collections.reverse(path);
return path;
}
Actually, if you can use also third libraries, i suggest you to look for a graph java library like JGraphT, and use the given functions for minimum paths. For example here is the reference for the Dijkstra JGraphT API.
Related
I am working on Dijkstra algorithm. The program that I have read the data from a text file. the program works fine if I input the relation in the program but it does not work when I try to read the input from text file.
the input to the program in the program itself is as following:
private static final Graph.Edge[] Arr = {
new Graph.Edge("a", "b", 1),
new Graph.Edge("a", "c", 1),
new Graph.Edge("a", "f", 1),
new Graph.Edge("b", "c", 1),
new Graph.Edge("b", "d", 1),
new Graph.Edge("c", "d", 1),
new Graph.Edge("c", "f", 1),
new Graph.Edge("d", "e", 1),
new Graph.Edge("e", "f", 1),
};
what I have tried to read from text file to be instead of this input is as following:
first, I count the number of the line to be the size of the array:
public static int count;
public static void countLines(String file) throws IOException
{
LineNumberReader lnr = new LineNumberReader(new FileReader(new File(file)));
lnr.skip(Long.MAX_VALUE);
Dijkstra.count=lnr.getLineNumber() + 1;
lnr.close();
}
The function that will do the reading from the text file and saving the data to the array is as following:
public static Graph.Edge[] readTextFile(String fileName) {
String line = null;
Graph.Edge[] Gr=new Graph.Edge[Dijkstra.count-1];
try {
FileReader fileReader = new FileReader("txt2.txt");
BufferedReader bufferedReader = new BufferedReader(fileReader);
int i=0;
while ((line = bufferedReader.readLine()) != null) {
String[] tokens = line.split("\\t+");
String s = tokens[0];
String e = tokens[2];
Gr[i] =new Graph.Edge(s, e, 1);
i=i+1;
}
bufferedReader.close();
} catch (FileNotFoundException ex) {
System.out.println("Unable to open file '" + fileName + "'");
} catch (IOException ex) {
System.out.println("Error reading file '" + fileName + "'");
}
return Gr;
}
these functions and the main are within some class called Dijkstra. the whole code is as following:
package shortestPath;
import java.util.Scanner;
import java.io.*;
import java.util.*;
public class Dijkstra {
/*private static final Graph.Edge[] Arr = {
new Graph.Edge("a", "b", 1),
new Graph.Edge("a", "c", 1),
new Graph.Edge("a", "f", 1),
new Graph.Edge("b", "c", 1),
new Graph.Edge("b", "d", 1),
new Graph.Edge("c", "d", 1),
new Graph.Edge("c", "f", 1),
new Graph.Edge("d", "e", 1),
new Graph.Edge("e", "f", 1),
};*/
public static int count;
//public static Graph.Edge[] GRAPH = new Graph.Edge[count] ;
public static void countLines(String file) throws IOException
{
LineNumberReader lnr = new LineNumberReader(new FileReader(new File(file)));
lnr.skip(Long.MAX_VALUE);
Dijkstra.count=lnr.getLineNumber() + 1; //Add 1 because line index starts at 0
// Finally, the LineNumberReader object should be closed to prevent resource leak
lnr.close();
//return Dijkstra.count;
}
public static Graph.Edge[] readTextFile(String fileName) {
String line = null;
Graph.Edge[] Gr=new Graph.Edge[Dijkstra.count-1];
try {
FileReader fileReader = new FileReader("txt2.txt");
BufferedReader bufferedReader = new BufferedReader(fileReader);
int i=0;
while ((line = bufferedReader.readLine()) != null) {
String[] tokens = line.split("\\t+");
String s = tokens[0];
String e = tokens[2];
Gr[i] =new Graph.Edge(s, e, 1);
i=i+1;
}
// Always close files.
bufferedReader.close();
} catch (FileNotFoundException ex) {
System.out.println("Unable to open file '" + fileName + "'");
} catch (IOException ex) {
System.out.println("Error reading file '" + fileName + "'");
}
//return Dijkstra.GRAPH;
return Gr;
}
private static final String START = "12";
private static final String END = "18";
public static void main(String[] args) throws IOException {
countLines("hsa00072.txt");
Graph.Edge[] GRAPH=readTextFile("hsa00072.txt");
Graph g = new Graph(GRAPH);
g.dijkstra(START);
g.printPath(END);
//g.printAllPaths();
}
}
class Graph {
private final Map<String, Vertex> graph; // mapping of vertex names to Vertex objects, built from a set of Edges
/** One edge of the graph (only used by Graph constructor) */
public static class Edge {
public final String v1, v2;
public final int dist;
public Edge(String v1, String v2, int dist) {
this.v1 = v1;
this.v2 = v2;
this.dist = dist;
}
}
/** One vertex of the graph, complete with mappings to neighbouring vertices */
public static class Vertex implements Comparable<Vertex> {
public final String name;
public int dist = Integer.MAX_VALUE; // MAX_VALUE assumed to be infinity
public Vertex previous = null;
public final Map<Vertex, Integer> neighbours = new HashMap<>();
public Vertex(String name) {
this.name = name;
}
private void printPath() {
if (this == this.previous) {
System.out.printf("%s", this.name);
} else if (this.previous == null) {
System.out.printf("%s(unreached)", this.name);
} else {
this.previous.printPath();
System.out.printf(" -> %s(%d)", this.name, this.dist);
}
}
public int compareTo(Vertex other) {
return Integer.compare(dist, other.dist);
}
}
/** Builds a graph from a set of edges */
public Graph(Edge[] edges) {
graph = new HashMap<>(edges.length);
//one pass to find all vertices
for (Edge e : edges) {
if (!graph.containsKey(e.v1)) graph.put(e.v1, new Vertex(e.v1));
if (!graph.containsKey(e.v2)) graph.put(e.v2, new Vertex(e.v2));
}
//another pass to set neighbouring vertices
for (Edge e : edges) {
graph.get(e.v1).neighbours.put(graph.get(e.v2), e.dist);
//graph.get(e.v2).neighbours.put(graph.get(e.v1), e.dist); // also do this for an undirected graph
}
}
/** Runs dijkstra using a specified source vertex */
public void dijkstra(String startName) {
if (!graph.containsKey(startName)) {
System.err.printf("Graph doesn't contain start vertex \"%s\"\n", startName);
return;
}
final Vertex source = graph.get(startName);
NavigableSet<Vertex> q = new TreeSet<>();
// set-up vertices
for (Vertex v : graph.values()) {
v.previous = v == source ? source : null;
v.dist = v == source ? 0 : Integer.MAX_VALUE;
q.add(v);
}
dijkstra(q);
}
/** Implementation of dijkstra's algorithm using a binary heap. */
private void dijkstra(final NavigableSet<Vertex> q) {
Vertex u, v;
while (!q.isEmpty()) {
u = q.pollFirst(); // vertex with shortest distance (first iteration will return source)
if (u.dist == Integer.MAX_VALUE) break; // we can ignore u (and any other remaining vertices) since they are unreachable
//look at distances to each neighbour
for (Map.Entry<Vertex, Integer> a : u.neighbours.entrySet()) {
v = a.getKey(); //the neighbour in this iteration
final int alternateDist = u.dist + a.getValue();
if (alternateDist < v.dist) { // shorter path to neighbour found
q.remove(v);
v.dist = alternateDist;
v.previous = u;
q.add(v);
}
}
}
}
/** Prints a path from the source to the specified vertex */
public void printPath(String endName) {
if (!graph.containsKey(endName)) {
System.err.printf("Graph doesn't contain end vertex \"%s\"\n", endName);
return;
}
graph.get(endName).printPath();
System.out.println();
}
/** Prints the path from the source to every vertex (output order is not guaranteed) */
public void printAllPaths() {
for (Vertex v : graph.values()) {
v.printPath();
System.out.println();
}
}
}
The text file is as following:
12 ECrel 15
15 ECrel 18
11 ECrel 12
12 ECrel 14
11 ECrel 14
11 ECrel 18
14 maplink 17
the problem is whenever I want to find the path like from node 12 to node 18 it will say 18(unreached) even if there is a path but it will not return the path. in case of the input in the program it works fine and return the path. the problem is only appears when trying to read from the text file.
There is something very strange going on here. I'll babble along as I work through it.
I get randomly different results (sometimes your program works as you wanted, sometimes not). Often they are different depending on whether I am running in debug mode or not.
So . . . it's time to look for a source of randomness. Clearly you're not using randomness directly/intentionally. So we should look somewhere else for the randomness.
I think I see two potential sources of randomness.
When you're traversing the NavigableSet, it's doing a lot of comparing equal values at first. That's necessary and makes sense, but it might lead to randomness, since it doesn't have to pick one particular order of how to present the elements to you.
You also use Maps in your algorithm, and there are no promises about what order their entrySets come back in.
My guess is that your algorithm is actually sensitive to the order in which things are presented to it. I haven't dug in enough to know which bits might be the problem, but maybe this section goes two different directions if two equally good routes are presented to it in different orders:
if (alternateDist < v.dist) { // shorter path to neighbour found
q.remove(v);
v.dist = alternateDist;
v.previous = u;
q.add(v);
}
and possibly one of those routes never leads to the destination you're looking for.
I would actually suggest getting out bits of paper and writing the vertices on them, and shuffling them whenever your algorithm calls for an iterator over map EntrySets.
My suspicion for why this works when reading from the source and fails when reading from code: different random seeds. That's it. It's technically prone to the same failure in both cases, it just happens to pick a working path in one JVM scenario and a non-working path in the other JVM scenario.
Sorry this is kind of fuzzy and really long. Maybe it will help.
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.
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:
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.
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.