Connecting nodes in a matrix for a graph - java

Hi I'm working on this little project which requires me to build a matrix in Java which resembles a chess board. I'm supposed to get the Knight to get from a point to another(In the way Knight moves). So I need to find the shortest way to get there in the end.
My problem is, I can't get to connect the edges to get to that point. I can find out if the vertex is a valid move but I can't seem to find a way to create nodes to get to that point. For Example,
0 XXXXX
1 XXXOX
2 XXXXX
3 XXKXX
4 XXXXX
5 XXXXX
I need to create nodes that connect K to O to find out shortest distance later.
PS. I'll be okay with just hints of how to get there or just some tips. Don't really need the exact code. Thank you very much!
I know it's a bad representation of matrix up there but spare me the critique please

A classic Breadth-First-Search is probably the simplest approach:
class Location {
int x;
int y;
List<Location> adjacent() {
// TODO return list of locations reachable in a single step
}
}
List<Location> findShortestPath(Location start, Location destination) {
Location[][] previous = new Location[8][8];
Deque<Location> queue = new ArrayDeque<>();
queue.add(start);
do {
Location loc = queue.poll();
for (Location n : loc.neighbors()) {
if (previous[n.x][n.y] == null) {
previous[n.x][n.y] = loc;
queue.add(n);
if (n.x == destination.x && n.y == destination.y) {
// we've found a way, let's reconstruct the list of steps
List<Location> path = new ArrayList<>();
for (Location l = n; l != start; l = previous[l.x][l.y]) {
path.add(l);
}
path.reverse();
return path;
}
}
}
} while (!queue.isEmpty());
return null; // no path exists
}
This code enumerates all paths from the start location. Therefore, if there is a path to destination, it will find it. In addition, because paths are enumerated in order or ascending length, the first such path will be a shortest one.

The chess board can be implemented by a 2d array. Each cell in the matrix can be considered to be a node (or vertex) in the graph. Edge is composed of two nodes (in this case two cells) one being the from or source [ lets call it Nod A] and other being the to or neighbor or destination node [ Lets call it node B].
Edge exits if there is a possibility of moving from node A to node B.
You can use Dijkstra's algorithm.
http://krishnalearnings.blogspot.in/2015/07/implementation-in-java-for-dijkstras.html
For Node with the Knight's position you can see the possibilities of the cells where Knight can move to and add in the Min Heap. The weight of each edge is constant. You just need to update the cost of the Node.

Related

A* Pathfinding Algorithm -- finding a path, but not optimal best path

I'm working on an A* algorithm. This is the code for the pathfinding method. For reference, this is the board I am working with: http://i.imgur.com/xaAzNSw.png?1 Each color tile represents a different heuristic value. For some unknown reason, it finds a path every single time, just not always the correct path. Here is the code for the pathfinding method. If anyone needs any clarifications, I'd be happy to provide them.
public List<Point> findPath(Point start, Point end) {
//declarations and instantiations
List<PathState> closedList = new ArrayList<PathState>(); //the nodes already considered
List<PathState> openList = new ArrayList<PathState>(); //nodes to be considered
openList.add(new PathState(start, end, tm)); //add starting point
PathState current = openList.get(0);
while(!current.isGoal()){
//sort open list to find the pathstate with the best hscore(sorts by hscore)
Collections.sort(openList);
current = openList.get(openList.size() - 1);
closedList.add(current);
openList.remove(current);
//get the valid children of current node
List<PathState> children = current.getChildren();;
if(!current.isGoal()){
for(int i = 0; i < children.size(); i++){
if(!closedList.contains(children.get(i))){
if(openList.contains(children.get(i))){
if(openList.get(openList.indexOf(children.get(i))).getgScore() > children.get(i).getgScore()){
//child is already on the open list, but this node has lower g value
//change g value and parent of node on open list
openList.get(openList.indexOf(children.get(i))).setG(children.get(i).getgScore());
openList.get(openList.indexOf(children.get(i))).changeParent(current);
}
}else{
//child not in closed list
openList.add(children.get(i));
//repaint the terrain panel with shades
tp.addAstarState(children.get(i));
tp.repaint();
try {
Thread.sleep(25);
} catch(Exception e) {
e.printStackTrace();
}
}
}
}
}
}
//returns the path from winning node to start for output
return current.getPath();
}
A* is basically Djikstra's algorithm but you direct your search to the destination by combining your distance function with an estimate of the remaining distance.
At node x, the cost or "score" is (distance_so_far) for djikstra
at A*, it is (distance_so_far + estimate_of_remaining_distance)
To make sure that A* finds the shortest path, the estimate_of_remaining_distance must be a true lower bound. That means it must always be less than the actual remaining distance. That means, you can never overestimate this distance otherwise it becomes an inexact heuristic in which case it won't necessarily find the shortest path.
This is a good reference: http://theory.stanford.edu/~amitp/GameProgramming/AStarComparison.html
It links to this reference which explains more about heuristic functions: http://theory.stanford.edu/~amitp/GameProgramming/Heuristics.html

Returning the path in Dijkstra's Algorithm

So, I've been implementing Dijkstra's algorithm for pathfinding through a maze I generate (I know some of you might think something like A* would be better, but Dijkstra's perfectly fits my needs), and I've run into a small issue. I feel like I'm overlooking something, but when I return the "path" from the start node to the end node, it returns the entire search path the algorithm took (every node it visited), and not the path to the node.
//Uses djikstra's algorithm to find the shortest path between two nodes
//"vertices" is the global ArrayList in the class with all vertices in the graph.
#Override
public ArrayList<Vertex> pathfind(Vertex v1, Vertex v2) {
ArrayList<Vertex> path = new ArrayList<Vertex>();
ArrayList<Vertex> unvisited = new ArrayList<Vertex>();
ArrayList<Vertex> visited = new ArrayList<Vertex>();
if (!vertices.contains(v1) || !vertices.contains(v2)) {
return path;
}
//initialize distances
v1.setDistance(0);
for(Vertex vert : vertices) {
if(vert != v1) {
vert.setDistance(Integer.MAX_VALUE);
}
unvisited.add(vert);
}
Vertex current = v1;
//begin
while (!unvisited.isEmpty()) {
//for all adjacent vertices that are unvisited
for (Vertex v : current.adjacentVertices()) {
if (!visited.contains(v)) {
//if the distance of that vertex is greater than
//the added distance of the current node + the edge connecting the two
int pathDist = current.getDistance() + findEdge(current, v).getElement();
if (v.getDistance() > pathDist) {
//assign the new distance
v.setDistance(pathDist);
}
}
}
//remove the current node from the visited set and add it to visited
visited.add(current);
unvisited.remove(current);
//add current node to the path
path.add(current);
//return if we found the destination
if (current == v2)) {
return path;
}
//else move to the lowest value node
current = findSmallest(unvisited);
}
return path;
}
I know it must be something painfully obvious but I'm hitting my head against the wall, any help would be appreciated. Thanks!
You might want to calculate the distances first/ stabilize the distance to minimum value using the algo, then run over the graph to get the nodes for the path.
As current = findSmallest(unvisited) might get you node from a path which is not connected.
Thanks for the help everyone, I ended up making a HashMap with links to the previous nodes, and traversed that back to the start.

Given a directed graph, find out whether there is a route between two nodes

I'm trying to solve this problem and i'm fairly new to graphs.
I tried BFS to figure this out but i'm not getting the right answer.
What am i doing wrong? Also, is there a better way of doing this, other than the approach i am using.
public static boolean isThereARoute(int[][] graph ,gNode n1 , gNode n2 ) {
// where can we move? - anywhere where the value of x and y is 1 - else can't move
// Start with node 1 and then traverse either BFS or DFS to see if the n2 is in the path anywhere
// using BFS.
//mark the ones where we can move as true
boolean[][] canMove= new boolean[graph.length][graph[0].length];
for(int i = 0;i<canMove.length;i++){
for(int j =0;j<canMove[0].length;j++){
if(graph[i][j]==-1){
canMove[i][j] = false;
}else{
canMove[i][j] = true;
}
}
}
// create a queue
Deque<gNode> queue = new LinkedList<gNode>();
// insert the first node into the queue
queue.add(n1);
while(!queue.isEmpty()){
gNode top = queue.poll();
int x = top.x1;
int y = top.y1;
// only check the ones where we can go
if( ( top.x1>=0 && top.x1<= graph.length-1) && (top.y1>=0 && top.y1<= (graph[0].length-1)) ){
if(canMove[top.x1][top.y1]){
if((top.x1 == n2.x1) && (top.y1 == n2.y1)){
// found our node;
return true;
}
// else haven't found any - add the nodes to the queue // allowed diagonals as well// therefore for each node
// there can be 8 neighbors
queue.add(new gNode(x-1,y));
queue.add(new gNode(x,y-1));
queue.add(new gNode(x+1,y));
queue.add(new gNode(x,y+1));
queue.add(new gNode(x-1,y-1));
queue.add(new gNode(x-1,y+1));
queue.add(new gNode(x+1,y+1));
queue.add(new gNode(x+1,y-1));
}
}
}
return false;
}
And for the check-
int[][] graphD = new int[][]{
{-1, 1,-1,-1,-1},
{-1,-1, 1,-1,-1},
{-1,-1, 1, 1,-1},
{-1,-1,-1,-1,-1},
{ 1,-1, 1,-1,-1}
};
ArrayList<gNode> nodes = new ArrayList<gNode>();
nodes.add(new gNode(0,0));//node A
nodes.add(new gNode(1,1)); // node B
nodes.add(new gNode(2,2)); // node C
nodes.add(new gNode(3,3)); // node D
nodes.add(new gNode(4,4)); // node E
/**
* A->b
* B->C
* C->C
* C->D
* E-A
*
*/
System.out.println(" is A -B connected?"+isThereARoute(graphD, nodes.get(0), nodes.get(1)));
System.out.println(" is A -D connected?"+isThereARoute(graphD, nodes.get(0), nodes.get(3)));
System.out.println(" is C -A connected?"+isThereARoute(graphD, nodes.get(3), nodes.get(0)));
System.out.println(" is A -E connected?"+isThereARoute(graphD, nodes.get(0), nodes.get(4)));
System.out.println(" is C -C connected?"+isThereARoute(graphD, nodes.get(2), nodes.get(2)));
I would say that BFS is the right algorithm to apply here, so it's just a problem with your BFS code. It looks like you're confused about how graphs are represented in an Adjacency Matrix.
if((top.x1 == n2.x1) && (top.y1 == n2.y1)){
// found our node;
return true;
}
This is checking if a specific entry in the adjacency matrix (an edge) has been reached, but you're just supposed to be checking if a given node is reachable.
You should change your gNode representation to use a single index (or just drop it and use an int instead), and do your BFS from the first node based off the adjacency matrix values.
If you need some additional help with understanding the algorithm / data structures, this page seems like a good reference: Adjacency matrices, BFS, DFS.
I'm not good at debugging more than 10-20 lines of code if I'm not really familiar with the language. However, I can tell you that there is a better overall approach to tell if there is a path between two nodes x and y, instead of just BFS or DFS starting from x. Namely, you can do BFS starting from x in the forward direction, and simultaneously do BFS from y in the reverse direction. I.e. starting with k=1, you find all vertices you can reach moving forward from x using a path of <= k edges, and you find all vertices you can reach moving reverse-direction from y using <= k edges, and you apply basic BFS principle to increase k by 1. For each k, you hash the vertices you can reach from x, and hash the vertices you can reach from y, and if you get a match w between the two sets then w is a midpoint in a path from x to y, so a path exists. The reason why this is preferable to BFS starting from x is that if your path from x to y has length K, then BFS starting at x will find all nodes reachable in K steps, which may be a huge set (worst-case exponential in K). But if you do it the way I proposed, then you can terminate when you reach k >= K/2, and the 2 sets of vertices reachable in K/2 steps will often be much smaller than a set of vertices reachable in K steps. So, when a path exists, you will typically find it much faster the way I proposed.
Approach to this can be.
1. BFS (most simple and efficient too)
2. Transitive closure (found using Floyd-Warshall algorithm).

Efficient algorithm to find all the paths from A to Z?

With a set of random inputs like this (20k lines):
A B
U Z
B A
A C
Z A
K Z
A Q
D A
U K
P U
U P
B Y
Y R
Y U
C R
R Q
A D
Q Z
Find all the paths from A to Z.
A - B - Y - R - Q - Z
A - B - Y - U - Z
A - C - R - Q - Z
A - Q - Z
A - B - Y - U - K - Z
A location cannot appear more than once in the path, hence A - B - Y - U - P - U - Z is not valid.
Locations are named AAA to ZZZ (presented here as A - Z for simplicity) and the input is random in such a way that there may or may not be a location ABC, all locations may be XXX (unlikely), or there may not be a possible path at all locations are "isolated".
Initially I'd thought that this is a variation of the unweighted shortest path problem, but I find it rather different and I'm not sure how does the algorithm there apply here.
My current solution goes like this:
Pre-process the list such that we have a hashmap which points a location (left), to a list of locations (right)
Create a hashmap to keep track of "visited locations". Create a list to store "found paths".
Store X (starting-location) to the "visited locations" hashmap.
Search for X in the first hashmap, (Location A will give us (B, C, Q) in O(1) time).
For-each found location (B, C, Q), check if it is the final destination (Z). If so store it in the "found paths" list. Else if it doesn't already exist in "visited locations" hashmap, Recurl to step 3 now with that location as "X". (actual code below)
With this current solution, it takes forever to map all (not shortest) possible routes from "BKI" to "SIN" for this provided data.
I was wondering if there's a more effective (time-wise) way of doing it. Does anyone know of a better algorithm to find all the paths from an arbitrary position A to an arbitrary position Z ?
Actual Code for current solution:
import java.util.*;
import java.io.*;
public class Test {
private static HashMap<String, List<String>> left_map_rights;
public static void main(String args[]) throws Exception {
left_map_rights = new HashMap<>();
BufferedReader r = new BufferedReader(new FileReader("routes.text"));
String line;
HashMap<String, Void> lines = new HashMap<>();
while ((line = r.readLine()) != null) {
if (lines.containsKey(line)) { // ensure no duplicate lines
continue;
}
lines.put(line, null);
int space_location = line.indexOf(' ');
String left = line.substring(0, space_location);
String right = line.substring(space_location + 1);
if(left.equals(right)){ // rejects entries whereby left = right
continue;
}
List<String> rights = left_map_rights.get(left);
if (rights == null) {
rights = new ArrayList<String>();
left_map_rights.put(left, rights);
}
rights.add(right);
}
r.close();
System.out.println("start");
List<List<String>> routes = GetAllRoutes("BKI", "SIN");
System.out.println("end");
for (List<String> route : routes) {
System.out.println(route);
}
}
public static List<List<String>> GetAllRoutes(String start, String end) {
List<List<String>> routes = new ArrayList<>();
List<String> rights = left_map_rights.get(start);
if (rights != null) {
for (String right : rights) {
List<String> route = new ArrayList<>();
route.add(start);
route.add(right);
Chain(routes, route, right, end);
}
}
return routes;
}
public static void Chain(List<List<String>> routes, List<String> route, String right_most_currently, String end) {
if (right_most_currently.equals(end)) {
routes.add(route);
return;
}
List<String> rights = left_map_rights.get(right_most_currently);
if (rights != null) {
for (String right : rights) {
if (!route.contains(right)) {
List<String> new_route = new ArrayList<String>(route);
new_route.add(right);
Chain(routes, new_route, right, end);
}
}
}
}
}
As I understand your question, Dijkstras algorithm cannot be applied as is, since shortest path problem per definition finds a single path in a set of all possible paths. Your task is to find all paths per-se.
Many optimizations on Dijkstras algorithm involve cutting off search trees with higher costs. You won't be able to cut off those parts in your search, as you need all findings.
And I assume you mean all paths excluding circles.
Algorithm:
Pump network into a 2dim array 26x26 of boolean/integer. fromTo[i,j].
Set a 1/true for an existing link.
Starting from the first node trace all following nodes (search links for 1/true).
Keep visited nodes in a some structure (array/list). Since maximal
depth seems to be 26, this should be possible via recursion.
And as #soulcheck has written below, you may think about cutting of paths you have aleady visted. You may keep a list of paths towards the destination in each element of the array. Adjust the breaking condition accordingly.
Break when
visiting the end node (store the result)
when visiting a node that has been visted before (circle)
visiting a node for which you have already found all paths to the destination and merge your current path with all the existing ones from that node.
Performance wise I'd vote against using hashmaps and lists and prefer static structures.
Hmm, while re-reading the question, I realized that the name of the nodes cannot be limited to A-Z. You are writing something about 20k lines, with 26 letters, a fully connected A-Z network would require far less links. Maybe you skip recursion and static structures :)
Ok, with valid names from AAA to ZZZ an array would become far too large. So you better create a dynamic structure for the network as well. Counter question: regarding performance, what is the best data structure for a less popuplate array as my algorithm would require? I' vote for an 2 dim ArrayList. Anyone?
What you're proposing is a scheme for DFS, only with backtracking.It's correct, unless you want to permit cyclic paths (you didn't specify if you do).
There are two gotchas, though.
You have to keep an eye on nodes you already visited on current path (to eliminate cycles)
You have to know how to select next node when backtracking, so that you don't descend on the same subtree in the graph when you already visited it on the current path.
The pseudocode is more or less as follows:
getPaths(A, current_path) :
if (A is destination node): return [current_path]
for B = next-not-visited-neighbor(A) :
if (not B already on current path)
result = result + getPaths(B, current_path + B)
return result
list_of_paths = getPaths(A, [A])
which is almost what you said.
Be careful though, as finding all paths in complete graph is pretty time and memory consuming.
edit
For clarification, the algorithm has Ω(n!) time complexity in worst case, as it has to list all paths from one vertex to another in complete graph of size n, and there are at least (n-2)! paths of form <A, permutations of all nodes except A and Z, Z>. No way to make it better if only listing the result would take as much.
Your data is essentially an adjacency list which allows you to construct a tree rooted at the node corresponding to A. In order to obtain all the paths between A & Z, you can run any tree traversal algorithm.
Of course, when you're building the tree you have to ensure that you don't introduce cycles.
I would proceed recursively where I would build a list of all possible paths between all pairs of nodes.
I would start by building, for all pairs (X, Y), the list L_2(X, Y) which is the list of paths of length 2 that go from X to Y; that's trivial to build since that's the input list you are given.
Then I would build the lists L_3(X, Y), recursively, using the known lists L_2(X, Z) and L_2(Z, Y), looping over Z. For example, for (C, Q), you have to try all Z in L_2(C, Z) and L_2(Z, Q) and in this case Z can only be R and you get L_3(C, Q) = {C -> R -> Q}. For other pairs, you might have an empty L_3(X, Y), or there could be many paths of length 3 from X to Y.
However you have to be careful here when building the paths here since some of them must be rejected because they have cycles. If a path has twice the same node, it is rejected.
Then you build L_4(X, Y) for all pairs by combining all paths L_2(X, Z) and L_3(Z, Y) while looping over all possible values for Z. You still remove paths with cycles.
And so on... until you get to L_17576(X, Y).
One worry with this method is that you might run out of memory to store those lists. Note however that after having computed the L_4's, you can get rid of the L_3's, etc. Of course you don't want to delete L_3(A, Z) since those paths are valid paths from A to Z.
Implementation detail: you could put L_3(X, Y) in a 17576 x 17576 array, where the element at (X, Y) is is some structure that stores all paths between (X, Y). However if most elements are empty (no paths), you could use instead a HashMap<Pair, Set<Path>>, where Pair is just some object that stores (X, Y). It's not clear to me if most elements of L_3(X, Y) are empty, and if so, if it is also the case for L_4334(X, Y).
Thanks to #Lie Ryan for pointing out this identical question on mathoverflow. My solution is basically the one by MRA; Huang claims it's not valid, but by removing the paths with duplicate nodes, I think my solution is fine.
I guess my solution needs less computations than the brute force approach, however it requires more memory. So much so that I'm not even sure it is possible on a computer with a reasonable amount of memory.

Finding the set of MinCut edges in a Preflow Push Network Flow Algorithm

I have an implementation of the preflow push network flow algorithm that returns the maximum flow of a flow network. What I need is to identify the set of saturated edges that form the cut in the graph.
In my current implementation, I look for saturated forward edges with empty backward edges in the graph for which the distance from the edge source to the edge target is greater than or equal to one (ie, the source has a greater height than the target). In case there is only one possible set of edges in the graph that satisfies the min cut, the algorithm works ok, but if the algorithm can find more than one cut in the graph then it returns all the saturated edges in the graph. I have copied my code below. Any help is highly appreciated.
public Set<Edge> cutEdges(){
for (String v_name : vertices.keySet()){
int v_id = vertices.get(v_name);
ArrayList<Edge> veList = residual_edges.get(v_id);
for (Edge ve : veList){
boolean reverseFound = false;
EdgeData vinfo = (EdgeData) ve.getData();
if (vinfo.getAvailable() == 0){
Vertex temp1 = ve.getFirstEndpoint();
Vertex temp2 = ve.getSecondEndpoint();
int u_id = (v_id != vertices.get(temp1.getName().toString()) ?
vertices.get(temp2.getName().toString()) : vertices.get(temp1.getName().toString()));
ArrayList<Edge> ueList = residual_edges.get(u_id);
for (Edge ue : ueList){
EdgeData uinfo = (EdgeData) ue.getData();
if (ue.getFirstEndpoint().getName().toString().equals(temp2.getName().toString()) &&
ue.getSecondEndpoint().getName().toString().equals(temp1.getName().toString())){
if (((VertexData)ue.getFirstEndpoint().getData()).getPreflowHeight() -
((VertexData)ue.getSecondEndpoint().getData()).getPreflowHeight() >= 1){
if (uinfo.getFlow() == 0)
continue;
}
reverseFound = true;
break;
}
}
if (!reverseFound){
if (((VertexData)temp1.getData()).getPreflowHeight() -
((VertexData)temp2.getData()).getPreflowHeight() >= 1)
cut_edges.add(ve);
}
}
}
}
return cut_edges;
}
I'll copy my answer from the question How can I find the minimum cut on a graph using a maximum flow algorithm?:
From the source vertex, do a depth-first search along edges that still
have residual capacity (i.e., non-saturated edges). The cut consists
of all edges that were "seen" (i.e., are incident on a visited
vertex), but were not traversed since they are saturated. As you
noted, there might be other saturated edges that are not part of the
minimum cut.

Categories