I have attempted to implement Dijkstra's algorithm from the Pseudocode on the Wikipedia page. I have set a condition after the Queue is polled that tests if the current node is the target node, b. If so, then the Algorithm is to break and return the path from a to b.
This condition will always be satisfied as I know that all nodes within the range of the Adjacency Matrix do indeed exist. The program is to model the connections of the London Underground map.
Anyway, I have been trying to figure this out for a while now, and thus far it eludes me. Maybe somebody can spot the issue. Oh, adj is just the adjacency matrix for my graph.
/**
Implementation of Dijkstra's Algorithm taken from "Introduction to
Algorithms" by Cormen, Leiserson, Rivest and Stein. Third edition.
d = Array of all distances.
pi = Previous vertices.
S = Set of vertices whose final shortest path weights have been
determined.
Q = Priority queue of vertices.
**/
public ArrayList<Integer> dijkstra(Integer a, Integer b){
final double[] d = new double[adj.length];
int[] pi = new int[adj.length];
HashSet<Integer> S = new HashSet<Integer>();
PriorityQueue<Integer> Q = new PriorityQueue<Integer>(d.length, new Comparator<Integer>(){
public int compare(Integer a, Integer b){
Double dblA = d[a-1];
Double dblB = d[b-1];
return dblA.compareTo(dblB);
}
});
for(int i=0; i<d.length; i++){
d[i] = Double.POSITIVE_INFINITY;
}
d[a] = 0f;
for(int i=0; i<d.length; i++){
Q.add(i+1);
}
while(Q.size() > 0){
int u = Q.poll();
if(u == b){
System.out.println("jjd");
ArrayList<Integer> path = new ArrayList<Integer>();
for(int i=pi.length-1; i>=0; i--){
path.add(pi[i]);
}
return path;
}
S.add(u);
if(d[u] == Double.POSITIVE_INFINITY){
break;
}
for(int v=0; v<adj.length; v++){
double tmp = d[u] + adj[u][v];
if(tmp < d[v]){
d[v] = tmp;
pi[v] = u;
}
}
}
return new ArrayList<Integer>();
}
}
EDIT:- After doing some debugging, it seems that the body of the while loop is being executed only once.
if(d[u] == Double.POSITIVE_INFINITY){
break;
}
for(int v=0; v<adj.length; v++){
double tmp = d[u] + adj[u][v];
if(tmp < d[v]){
d[v] = tmp;
pi[v] = u;
}
}
The changing of the d values in the loop body doesn't rearrange the priority queue, so unless the element that happened to be at the top of the queue after popping the initial node is one of its neighbours, you will have d[u] == Double.POSITIVE_INFINITY in the next iteration and break then.
In Dijkstra's algorithm, it is important that the queue be updated when the distance of a node changes. java.util.PriorityQueue<E> doesn't offer that functionality, so using that is non-trivial, I see no way to use it other than removing and re-adding the updated nodes on every update. That is of course not very efficient, since removal is O(size).
The inefficiency can be mitigated by not having all nodes in the queue. Star with adding only the initial node, and in the loop, insert only the neighbours not yet seen, remove and reinsert the neighbours that already are in the queue. That keeps the queue shorter, and makes removal cheaper on average.
For an efficient implementation, you would need a custom priority queue that allows faster (O(log size)?) update of priorities.
If you get 'jjd' outputted in the console when you run the program from your System.out.println your problem should be this:
if(u == b){
System.out.println("jjd");
ArrayList<Integer> path = new ArrayList<Integer>();
for(int i=pi.length-1; i>=0; i--){
path.add(pi[i]);
}
return path;
When you are calling the 'return path;' you actually break the whole method and return 'path'.
Related
I tried Dijkstras algorithm and got confused between 2 implemntation, one keeps track of visited nodes (code1) and other don't keep the track (code2).
Code1:
dis[S] = 0; //S is source
vis[S] = 1;
PriorityQueue<Node> queue = new PriorityQueue<>();
queue.offer(new Node(S, 0));
while(!queue.isEmpty()){
Node node = queue.poll();
int u = node.v;
vis[u] = 1;
for(Node n: adj1.get(u)){
int v = n.v;
int w = n.w;
if(vis[v] == 0){
if(dis[u]+w < dis[v]){
dis[v] = dis[u]+w;
}
queue.offer(n);
}
}
}
`
code2:
dis[S] = 0;
//vis[S] = 1;
PriorityQueue<Node> queue = new PriorityQueue<>();
queue.offer(new Node(S, 0));
while(!queue.isEmpty()){
Node node = queue.poll();
int u = node.v;
// vis[u] = 1;
for(Node n: adj1.get(u)){
int v = n.v;
int w = n.w;
// if(vis[v] == 0){
if(dis[u]+w < dis[v]){
dis[v] = dis[u]+w;
queue.offer(n);
}
// }
}
}
Code 1 fails some test cases code 2 passes all test cases. can anyone explain why code 1 fails like what are the edge cases i am missing.
Both of your implementations are incorrect. "code 2" might work, but it's probably slow.
The most obvious problem in both implementations is that your priority queue is full of edges. In Dijkstra's algorithm, the queue orders vertices by their currently best discovered cost. There is just no way that your priority queue could be doing this properly.
I would guess that you're actually ordering edges by weight. The will give you vertices in the wrong order, which could cause "code 1" to fail because of the visited check.
The next problem is the implementation of the visited check. If you're not using a heap that supports a decrease_key() operation, then you have to add a vertex to the queue every time you decrease the weight, so it could end up in the queue multiple times. When it comes out of the queue, you will know its best cost, so you can save time by ignoring the other instances in the queue when you see them.
You do not use the visited check to ensure that you only add the vertex once, because then keys can't be decreased and your implementation is broken.
A proper implementation looks like this:
// initialize dis to max value
for (int i=0; i<dis.length; ++i) {
dis[i] = Integer.MAX_VALUE;
}
dis[S] = 0; //S is source
// Note that S isn't scanned yet, so vis[S] == 0
PriorityQueue<PriorityNode> queue = new PriorityQueue<>();
queue.offer(new PriorityNode(S, 0));
while(!queue.isEmpty()){
PriorityNode node = queue.poll();
int u = node.vertex;
if (vis[u] != 0) {
// already resolved this vertex
continue;
}
vis[u] = 1;
for(Edge n: adj1.get(u)){
int v = n.v;
int w = n.w;
if(dis[u]+w < dis[v]){
dis[v] = dis[u]+w;
// We found a better cost for v
queue.offer(new PriorityNode(v, dis[v]));
}
}
}
How do we perform depth first search on a directed graph using an adjacency matrix in which it explores all of the vertices starting from a random vertex? I attempted to implement dfs, but its only exploring the vertices that are reachable from the starting vertex.
public static void dfs(int [] [] adjMatrix, int startingV,int n)
{
boolean [] visited = new boolean[n];
Stack<Integer> s = new Stack<Integer>();
s.push(startingV);
while(!s.isEmpty())
{
int vertex = s.pop();
if(visited[vertex]==false)
{
System.out.print("\n"+(v));
visited[vertex]=true;
}
for ( int i = 0; i < n; i++)
{
if((adjMatrix[vertex][i] == true) && (visited[i] == false))
{
s.push(vertex);
visited[I]=true;
System.out.print(" " + i);
vertex = i;
}
}
}
}
}
In a directed graph there might be no node from which you can reach all other nodes. So what do you expect in this case?
If there is at least one node from which you can reach all other nodes you only do now know which one it is, you can select a random one, go against the direction of an incoming edge to find a root node from which you can reach all other nodes.
Your code has a couple of issues, one of which is that you do a int vertex = s.pop(); and later an s.push(vertex); with the same vertex. The latter should probably be s.push(i); instead.
The easiest way to implement DF traversal is to just use recursion. Then the code decays to
function dfs(v) {
if v not visited before {
mark v as visited;
for every adjacent vertex a of v do {
dfs(a);
}
do something with v; // this is *after* all descendants have been visited.
}
}
Of course, every recursive implementation can be equivalently implemented using a stack and iteration instead, but in your case that'd be somewhat more complicated because you'd not only have to store the current vertex on the stack but also the state of iteration over its descendants (loop variable i in your case).
When I read solution to knapsack problem (http://en.wikipedia.org/wiki/Knapsack_problem), I couldn't understand why there is iteration number n in the argument. It seems we can come to leaf use case by checking the passed limit. Ex. the 15KG backpack problem, solution seems like:
Value(n, W){ // W = limit, n = # items still to choose from
if (n == 0) return 0;
if (arr[n][W] != unknown) return arr[n][W]; // <- add memoize
if (s[n] > W) result = Value(n-1,W);
else result = max{v[n] + Value(n-1, W-w[n]), Value(n-1, W)};
arr[n][W] = result; // <- add memoize
return result;
}
My non-memoize method looks like the below, which is easier to understand, at least for me, and also could be improved with memoization.
static int n =5;
static int [] w = new int[]{12,2,1,4,1}; //weight
static int [] v = new int[]{4,2,1,10,2}; //value
public static int knapSack(int wt){
int maxValue = 0,vtemp = 0, wtemp =0;
if (wt ==0) return 0;
for (int i=0; i<n; i++){
if (w[i] > wt) continue;
int tmp = v[i] + knapSack(wt - w[i]);
if (tmp > maxValue){
maxValue = tmp;
vtemp = v[i];
wtemp = w[i];
}
}
System.out.println("wt="+wt + ",vtemp="+vtemp+",wtemp="+wtemp+",ret max="+maxValue);
return maxValue;
}
So my question is:
why do we need n for argument?
statement if (s[n] > W) result = Value(n-1,W); make me even harder to understand why
I see the same big O for memoized version of my approach. Any other difference?
Thanks.
You're actually solving a different problem. The first piece of code (with n) solves the 0-1 knapsack problem, where you can choose to take at most one of any particular item (i.e. there is no "copying" of items). In that case, you need n to keep track of which items you've already used up.
In the second piece of code, you're solving the unbounded knapsack problem, in which you can take every item an unlimited number of times.
They're both forms of the NP-complete knapsack problem, but they have different solutions.
I have a Graph class with a bunch of nodes, edges, etc. and I'm trying to perform Dijkstra's algorithm. I start off adding all the nodes to a priority queue. Each node has a boolean flag for whether it is already 'known' or not, a reference to the node that comes before it, and an int dist field that stores its length from the source node. After adding all the nodes to the PQ and then flagging the source node appropriately, I've noticed that the wrong node is pulled off the PQ first. It should be that the node with the smallest dist field comes off first (since they are all initialized to a a very high number except for the source, the first node off the PQ should be the source... except it isn't for some reason).
Below is my code for the algorithm followed by my compare method within my Node class.
public void dijkstra() throws IOException {
buildGraph_u();
PriorityQueue<Node> pq = new PriorityQueue<>(200, new Node());
for (int y = 0; y < input.size(); y++) {
Node v = input.get(array.get(y));
v.dist = 99999;
v.known = false;
v.prnode = null;
pq.add(v);
}
source.dist = 0;
source.known = true;
source.prnode = null;
int c=1;
while(c != input.size()) {
Node v = pq.remove();
//System.out.println(v.name);
//^ Prints a node that isn't the source
v.known = true;
c++;
List<Edge> listOfEdges = getAdjacent(v);
for (int x = 0; x < listOfEdges.size(); x++) {
Edge edge = listOfEdges.get(x);
Node w = edge.to;
if (!w.known) {
int cvw = edge.weight;
if (v.dist + cvw < w.dist) {
w.dist = v.dist + cvw;
w.prnode = v;
}
}
}
}
}
public int compare (Node d1, Node d2) {
int dist1 = d1.dist;
int dist2 = d2.dist;
if (dist1 > dist2)
return 1;
else if (dist1 < dist2)
return -1;
else
return 0;
}
Can anyone help me find the issue with my PQ?
The priority queue uses assumption that order doesn't change after you will insert the element.
So instead of inserting all of the elements to priority queue you can:
Start with just one node.
Loop while priority queue is not empty.
Do nothing, if element is "known".
Whenever you find smaller distance add it to priority queue with "right" weight.
So you need to store a sth else in priority queue, a pair: distance at insertion time, node itself.
I'm trying to implement a program to solve the n-puzzle problem.
I have written a simple implementation in Java that has a state of the problem characterized by a matrix representing the tiles. I am also able to auto-generate the graph of all the states giving the starting state. On the graph, then, I can do a BFS to find the path to the goal state.
But the problem is that I run out of memory and I cannot even create the whole graph.
I tried with a 2x2 tiles and it works. Also with some 3x3 (it depends on the starting state and how many nodes are in the graph). But in general this way is not suitable.
So I tried generating the nodes at runtime, while searching. It works, but it is slow (sometimes after some minutes it still have not ended and I terminate the program).
Btw: I give as starting state only solvable configurations and I don't create duplicated states.
So, I cannot create the graph. This leads to my main problem: I have to implement the A* algorithm and I need the path cost (i.e. for each node the distance from the starting state), but I think I cannot calculate it at runtime. I need the whole graph, right? Because A* does not follow a BFS exploration of the graph, so I don't know how to estimate the distance for each node. Hence, I don't know how to perform an A* search.
Any suggestion?
EDIT
State:
private int[][] tiles;
private int pathDistance;
private int misplacedTiles;
private State parent;
public State(int[][] tiles) {
this.tiles = tiles;
pathDistance = 0;
misplacedTiles = estimateHammingDistance();
parent = null;
}
public ArrayList<State> findNext() {
ArrayList<State> next = new ArrayList<State>();
int[] coordZero = findCoordinates(0);
int[][] copy;
if(coordZero[1] + 1 < Solver.SIZE) {
copy = copyTiles();
int[] newCoord = {coordZero[0], coordZero[1] + 1};
switchValues(copy, coordZero, newCoord);
State newState = checkNewState(copy);
if(newState != null)
next.add(newState);
}
if(coordZero[1] - 1 >= 0) {
copy = copyTiles();
int[] newCoord = {coordZero[0], coordZero[1] - 1};
switchValues(copy, coordZero, newCoord);
State newState = checkNewState(copy);
if(newState != null)
next.add(newState);
}
if(coordZero[0] + 1 < Solver.SIZE) {
copy = copyTiles();
int[] newCoord = {coordZero[0] + 1, coordZero[1]};
switchValues(copy, coordZero, newCoord);
State newState = checkNewState(copy);
if(newState != null)
next.add(newState);
}
if(coordZero[0] - 1 >= 0) {
copy = copyTiles();
int[] newCoord = {coordZero[0] - 1, coordZero[1]};
switchValues(copy, coordZero, newCoord);
State newState = checkNewState(copy);
if(newState != null)
next.add(newState);
}
return next;
}
private State checkNewState(int[][] tiles) {
State newState = new State(tiles);
for(State s : Solver.states)
if(s.equals(newState))
return null;
return newState;
}
#Override
public boolean equals(Object obj) {
if(this == null || obj == null)
return false;
if (obj.getClass().equals(this.getClass())) {
for(int r = 0; r < tiles.length; r++) {
for(int c = 0; c < tiles[r].length; c++) {
if (((State)obj).getTiles()[r][c] != tiles[r][c])
return false;
}
}
return true;
}
return false;
}
Solver:
public static final HashSet<State> states = new HashSet<State>();
public static void main(String[] args) {
solve(new State(selectStartingBoard()));
}
public static State solve(State initialState) {
TreeSet<State> queue = new TreeSet<State>(new Comparator1());
queue.add(initialState);
states.add(initialState);
while(!queue.isEmpty()) {
State current = queue.pollFirst();
for(State s : current.findNext()) {
if(s.goalCheck()) {
s.setParent(current);
return s;
}
if(!states.contains(s)) {
s.setPathDistance(current.getPathDistance() + 1);
s.setParent(current);
states.add(s);
queue.add(s);
}
}
}
return null;
}
Basically here is what I do:
- Solver's solve has a SortedSet. Elements (States) are sorted according to Comparator1, which calculates f(n) = g(n) + h(n), where g(n) is the path cost and h(n) is a heuristic (the number of misplaced tiles).
- I give the starting configuration and look for all the successors.
- If a successor has not been already visited (i.e. if it is not in the global set States) I add it to the queue and to States, setting the current state as its parent and parent's path + 1 as its path cost.
- Dequeue and repeat.
I think it should work because:
- I keep all the visited states so I'm not looping.
- Also, there won't be any useless edge because I immediately store current node's successors. E.g.: if from A I can go to B and C, and from B I could also go to C, there won't be the edge B->C (since path cost is 1 for each edge and A->B is cheaper than A->B->C).
- Each time I choose to expand the path with the minimum f(n), accordin to A*.
But it does not work. Or at least, after a few minutes it still can't find a solution (and I think is a lot of time in this case).
If I try to create a tree structure before executing A*, I run out of memory building it.
EDIT 2
Here are my heuristic functions:
private int estimateManhattanDistance() {
int counter = 0;
int[] expectedCoord = new int[2];
int[] realCoord = new int[2];
for(int value = 1; value < Solver.SIZE * Solver.SIZE; value++) {
realCoord = findCoordinates(value);
expectedCoord[0] = (value - 1) / Solver.SIZE;
expectedCoord[1] = (value - 1) % Solver.SIZE;
counter += Math.abs(expectedCoord[0] - realCoord[0]) + Math.abs(expectedCoord[1] - realCoord[1]);
}
return counter;
}
private int estimateMisplacedTiles() {
int counter = 0;
int expectedTileValue = 1;
for(int i = 0; i < Solver.SIZE; i++)
for(int j = 0; j < Solver.SIZE; j++) {
if(tiles[i][j] != expectedTileValue)
if(expectedTileValue != Solver.ZERO)
counter++;
expectedTileValue++;
}
return counter;
}
If I use a simple greedy algorithm they both work (using Manhattan distance is really quick (around 500 iterations to find a solution), while with number of misplaced tiles it takes around 10k iterations). If I use A* (evaluating also the path cost) it's really slow.
Comparators are like that:
public int compare(State o1, State o2) {
if(o1.getPathDistance() + o1.getManhattanDistance() >= o2.getPathDistance() + o2.getManhattanDistance())
return 1;
else
return -1;
}
EDIT 3
There was a little error. I fixed it and now A* works. Or at least, for the 3x3 if finds the optimal solution with only 700 iterations. For the 4x4 it's still too slow. I'll try with IDA*, but one question: how long could it take with A* to find the solution? Minutes? Hours? I left it for 10 minutes and it didn't end.
There is no need to generate all state space nodes for solving a problem using BFS, A* or any tree search, you just add states you can explore from current state to the fringe and that's why there is a successor function.
If BFS consumes much memory it is normal. But I don't know exactly fro what n it would make problem. Use DFS instead.
For A* you know how many moves you made to come to current state and you can estimate moves need to solve problem, simply by relaxing problem. As an example you can think that any two tiles can replace and then count moves needed to solve the problem. You heuristic just needs to be admissible ie. your estimate be less then actual moves needed to solve the problem.
add a path cost to your state class and every time you go from a parent state P to another state like C do this : c.cost = P.cost + 1 this will compute the path cost for every node automatically
this is also a very good and simple implementation in C# for 8-puzzle solver with A* take a look at it you will learn many things :
http://geekbrothers.org/index.php/categories/computer/12-solve-8-puzzle-with-a