Introduction to Graph Theory: Finding The Shortest Path (Part 2) (Posted on February 23rd, 2013)

A couple of weeks ago I did an introduction to graph theory using Dijkstra's algorithm. I received some awesome feedback so this week I want to take it a step further and build on that using the A* algorithm. The big difference between A* and Dijkstra's algorithm is the addition of a heuristic function. This heuristic function allows us to give a best guess of which path to take rather than always taking the path that is the shortest distance from the source node. If you're a gamer or someone looking to get into game development this algorithm is the basis of how path finding is done in a lot of games.

Dijkstra's Algorithm Refresher

Given a source node in a graph we examine all connected edges for the shortest distance from that node. We then mark the source node as visited so we don't have to check the edges again. Based off our edge examinations we then go to the next closest node that hasn't been visited. We repeat this process until we reach our destination node. Then we check the path we took to get there and print that out.

If you'd like a more detailed explanation definitely check out my blog post on the algorithm.

The Heuristic Function

The goal of this function is to give us a dynamic way to pick a path to our target node. An example of this would be planning a route home from work. You may normally take the highway but as you get closer to the highway you realize that there is an accident blocking the road. So instead of taking the highway home you use back roads which get you home faster. You took a guess that the highway would be the quickest way home but after checking the path it turned out you need take an alternate route. The heuristic function is used to give a best guess of the path to take.

There are several different ways to come up with a heuristic function but it is important to make sure that the function is admissible (never overestimates the cost of reaching the goal). A common heuristic function is the Chebyshev Distance which allows us to move diagonally along a grid rather than just up, down, and side to side like the Manhattan Distance. If you're making something where diagonal movement isn't allowed then definitely use the Manhattan Distance. The Chebyshev Distance states that the distance between two nodes is the greatest of their differences along any coordinate dimension. The code for this calculation is easy to implement.

chebyshev_distance = [(current.x - target.x).abs, (current.y - target.y).abs].max

The Setup

Just need one gem for this one. PriorityQueue will allow us to have a heap where we can change the priority and have the tree automatically rebalance which is nice.

gem install PriorityQueue

Creating the Graph

Let's start by creating a grid of a specified size. This grid will be our graph and will be a square for simplicity. For A* each node in the graph will need to store some extra information about it so let's just create a Node class that will store this information.

class Node
    def initialize(x, y)
        @x = x
        @y = y
        @obstacle = false
        @g_score = Float::INFINITY
    end
    
    def x()
        return @x
    end
    
    def y()
        return @y
    end
    
    def set_obstacle()
        @obstacle = true
    end
    
    def obstacle()
        return @obstacle
    end
    
    def set_g_score(score)
        @g_score = score
    end
    
    def g_score()
        return @g_score
    end
    
    def to_s
        return "(" + @x.to_s + ", " + @y.to_s + ", " + @obstacle.to_s + ")"
    end
end

The x and y variables will give us our coordinate position, the obstacle variable will tell us if we can pass through this position or not, and the g_score variable will be the best distance from the source node to this node. The g_score for each node starts at infinity since no paths have been calculated yet.

Next we need to create a grid out of these Nodes. So let's create a graph class and insert a grid of a size we choose.

class Graph
    def initialize(size)
        @size = size-1 # Last index in 0 based array
        @grid = []
        for y in 0..@size
          row = []
          for x in 0..@size
            row.push(Node.new(x, y))
          end
          @grid.push(row)
        end
    end
    
    def to_s
        return @grid.inspect
    end
end

Our graph takes a variable called size and creates a square of nodes of that size. Here's basically how our graph looks in memory if we make a size 8 graph.

0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0     

Something to keep in mind is that the ordered pair (0,0) is at the top left. So as Y increases you actually go down instead of up. This just makes array access easier. Otherwise you'll need to convert the x and y variables every time to map to the bottom of the graph which is definitely doable. So just remember (0,0) is at the top left and our positive y axis is pointed down.

Implementing A*

Before we start here is a great graphic from Wikipedia that shows how the algorithm works.

The algorithm will take in the starting x and y position as well as the finishing x and y position. We can then convert those coordinates into the actual nodes they are referencing. We can also use this time to initialize our variables that will be keeping track of our nodes.

def shortest_path(start_x, start_y, finish_x, finish_y)
        
    start = @grid[start_y][start_x]
    finish = @grid[finish_y][finish_x]
    
    visited = Set.new # The set of nodes already evaluated
    previous = {} # Previous node in optimal path from source
    previous[start] = 0
    f_score = PriorityQueue.new
        
end

Since we'll never visit the same node twice we want to make sure we don't waste time evaluating the same node more than once so we create a set of visited nodes for easy O(1) checking. We'll also want to keep track of how we got to a node. We keep track of nodes the same way as we do in Dijkstra's algorithm. A* improves on Dijkstra's by having an f_score. The f_score variable will be a min-heap (priority queue) of a node's distance from the source + the heuristic calculation. Since Set and PriorityQueue are not implemented by default in Ruby let's go ahead and require them at the top of our file.

require 'priority_queue'
require 'set'

A node at most can have 8 other touching nodes (up-left, up, up-right, right, down-right, down, down-left, and left). In order to evaluate these 8 nodes that could be possibly touching the node we're looking at I'm going to create an array of all possible combinations.

# All possible ways to go in a node
dx = [1, 1, 0, -1, -1, -1, 0, 1]
dy = [0, 1, 1, 1, 0, -1, -1, -1]

Using this array we'll always check the node to the right first. So if our starting node is (0,0) then the next node we evaluate is (0 + dx[0], 0 + dy[0]) = (1,0). This will be easier to see when we actually use it for the code. Right now we're just initializing it.

The final initialization step will be to set our start node's g_score to 0 and calculate the f_score. To calculate the f_score we'll need to implement the heuristic function (Chebyshev Distance) we talked about earlier. The code so far looks like this:

def shortest_path(start_x, start_y, finish_x, finish_y)
        
    def heuristic(current, target)
        return [(current.x - target.x).abs, (current.y - target.y).abs].max
    end
    
    start = @grid[start_y][start_x]
    finish = @grid[finish_y][finish_x]
    
    visited = Set.new # The set of nodes already evaluated
    previous = {} # Previous node in optimal path from source
    previous[start] = 0
    f_score = PriorityQueue.new
    
    # All possible ways to go in a node
    dx = [1, 1, 0, -1, -1, -1, 0, 1]
    dy = [0, 1, 1, 1, 0, -1, -1, -1]
    
    start.set_g_score(0) # Cost from start along best known path
    f_score[start] = start.g_score + heuristic(start, finish) # Estimated total cost from start to finish
end

Now that everything is setup let's start churning through nodes that need to be evaluated.

while !f_score.empty?
    current = f_score.delete_min_return_key # Node with smallest f_score
    visited.add(current)
end

This just grabs the lowest f_score from our priority queue and saves the node off to the current variable and adds it to the visited set so we know not to check it again.

Next we want to evaluate all the nodes that touch the current node. This is where our dx and dy arrays come in to play.

# Examine all directions for the next path to take
for direction in 0..7
    new_x = current.x + dx[direction]
    new_y = current.y + dy[direction]
    
    if new_x < 0 or new_x > @size or new_y < 0 or new_y > @size #Check for out of bounds
        next # Try next configuration
    end
end

The direction variable will be our index in the dx and dy array. We check to see if a node exists in each of the 8 possible directions. If we get a negative number or the value is greater than the size of the grid than we know we're on the edge of the grid. Since we can't check nodes outside of the grid we just say next which takes us to the next iteration of the for loop.

Once we get past the out of bounds check we know that the node exists in our grid. We'll call this node neighbor since it's adjacent to our current node. We then check if we've visited this node before, if it's set to be evaluated later, or if it's an obstacle. In any of the cases we don't want to evaluate any node more than once, unless it's an obstacle which we don't want to evaluate at all, so we skip that node and go to the next node.

# Examine all directions for the next path to take
for direction in 0..7
    new_x = current.x + dx[direction]
    new_y = current.y + dy[direction]
    
    if new_x < 0 or new_x > @size or new_y < 0 or new_y > @size #Check for out of bounds
        next # Try next configuration
    end
    
    neighbor = @grid[new_y][new_x]
    
    # Check if we've been to a node or if it is an obstacle
    if visited.include? neighbor or f_score.has_key? neighbor or neighbor.obstacle
        next
    end
end

When navigating the grid it's important to remember that not all paths are created equal. Think about a square with a side length of 10. The edge distance on any side of the square is going to be 10. However, if we want go diagonally across the square we have to bust out some Pythagoras. 10² + 10² = 200. When we take the square root of 200 we get about 14.1. One optimization that a lot of games make is rounding this number to 14 so you don't have to worry about floating point calculations. Let's go ahead and model that for our A* implementation. All diagonals will have a distance of 14 and all non-diagonals will have a distance of 10.

#dx = [1, 1, 0, -1, -1, -1, 0, 1]
#dy = [0, 1, 1, 1, 0, -1, -1, -1]
# Examine all directions for the next path to take
for direction in 0..7
    new_x = current.x + dx[direction]
    new_y = current.y + dy[direction]
    
    if new_x < 0 or new_x > @size or new_y < 0 or new_y > @size #Check for out of bounds
        next # Try next configuration
    end
    
    neighbor = @grid[new_y][new_x]
    
    # Check if we've been to a node or if it is an obstacle
    if visited.include? neighbor or f_score.has_key? neighbor or neighbor.obstacle
        next
    end
    
    if direction % 2 == 1
        tentative_g_score = current.g_score + 14 # traveled so far + distance to next node diagonal
    else
        tentative_g_score = current.g_score + 10 # traveled so far + distance to next node vertical or horizontal
    end
end

Our direction variable is essentially the index for our dx and dy arrays. All odd indices are diagonal paths. You can tell this by the fact that there is a 1 or -1 in both the dx and dy array at the same position. So when we're on an odd index we set our tentative_g_score to the current node's g_score + 14 which is our diagonal distance.

We're almost done! We just need to relax. Our relax function will essential be the same as our Dijkstra's implementation.

# Examine all directions for the next path to take
for direction in 0..7
    new_x = current.x + dx[direction]
    new_y = current.y + dy[direction]
    
    if new_x < 0 or new_x > @size or new_y < 0 or new_y > @size #Check for out of bounds
        next # Try next configuration
    end
    
    neighbor = @grid[new_y][new_x]
    
    # Check if we've been to a node or if it is an obstacle
    if visited.include? neighbor or f_score.has_key? neighbor or neighbor.obstacle
        next
    end
    
    if direction % 2 == 1
        tentative_g_score = current.g_score + 14 # traveled so far + distance to next node diagonal
    else
        tentative_g_score = current.g_score + 10 # traveled so far + distance to next node vertical or horizontal
    end
    
    # If there is a new shortest path update our priority queue (relax)
    if tentative_g_score < neighbor.g_score
        previous[neighbor] =  current
        neighbor.set_g_score(tentative_g_score)
        f_score[neighbor] = neighbor.g_score + heuristic(neighbor, finish)
    end
end

We're basically checking to see if our new path is going to be shorter than the previous path we found. If it is let's update how we get there, the distance to get there, and let's add the node to our priority queue to be evaluated in the future.

After this all that's left to do is simply print out the path. We can use the same procedure as we used for Dijkstra's. That is when get the current node we then check to see if the current variable is the same node as our finish variable. If it is print out the path and return. I also created a print_path function so that I could see the path graphically. Here's the necessary code to traverse the grid from the finish node back to the start node:

def print_path(path)
    for y in 0..@size
        for x in 0..@size
            if @grid[y][x].obstacle
                print "X "
            elsif path.include? @grid[y][x]
                print "- "
            else
                print "0 "
            end
        end
        print "\n"
    end
end

if current == finish
    path = Set.new
    while previous[current]
        path.add(current)
        current = previous[current]
    end
    
    print_path(path)
    return "Path found"
end

At the end of the shortest_path function we can also return "Failed to find path" if no path can be found. Now we have all we need to test our code. Let's try some configurations.

g = Graph.new(8)
g.set_obstacle(1,0)
g.set_obstacle(1,1)
g.set_obstacle(1,2)
g.set_obstacle(1,3)
g.set_obstacle(1,4)
g.set_obstacle(1,5)
g.set_obstacle(1,6)
puts g.shortest_path(0,0,4,2)

- X 0 0 0 0 0 0 
- X 0 0 0 0 0 0 
- X 0 0 - 0 0 0 
- X 0 - 0 0 0 0 
- X - 0 0 0 0 0 
- X - 0 0 0 0 0 
- X - 0 0 0 0 0 
0 - 0 0 0 0 0 0 
Path found


g = Graph.new(8)
g.set_obstacle(1,1)
g.set_obstacle(2,2)
g.set_obstacle(3,3)
g.set_obstacle(4,4)
g.set_obstacle(5,5)
g.set_obstacle(6,6)
g.set_obstacle(2,1)
g.set_obstacle(3,2)
g.set_obstacle(4,3)
g.set_obstacle(5,4)
g.set_obstacle(6,5)
puts g.shortest_path(0,2,6,3)

0 - - - 0 0 0 0 
- X X 0 - 0 0 0 
- 0 X X 0 - 0 0 
0 0 0 X X 0 - 0 
0 0 0 0 X X 0 0 
0 0 0 0 0 X X 0 
0 0 0 0 0 0 X 0 
0 0 0 0 0 0 0 0 
Path found

Pretty cool right? I've posted the final source code below for reference.

Final Source Code

require 'priority_queue'
require 'set'

class Node
    def initialize(x, y)
        @x = x
        @y = y
        @obstacle = false
        @g_score = Float::INFINITY
    end
    
    def x()
        return @x
    end
    
    def y()
        return @y
    end
    
    def set_obstacle()
        @obstacle = true
    end
    
    def obstacle()
        return @obstacle
    end
    
    def set_g_score(score)
        @g_score = score
    end
    
    def g_score()
        return @g_score
    end
    
    def to_s
        return "(" + @x.to_s + ", " + @y.to_s + ", " + @obstacle.to_s + ")"
    end
end

class Graph
    def initialize(size)
        @size = size-1 # Last index in 0 based array
        @grid = []
        for y in 0..@size
          row = []
          for x in 0..@size
            row.push(Node.new(x, y))
          end
          @grid.push(row)
        end
    end
  
    def set_obstacle(x, y)
        @grid[y][x].set_obstacle()
    end
    
    def shortest_path(start_x, start_y, finish_x, finish_y)
        
        def heuristic(current, target)
            return [(current.x - target.x).abs, (current.y - target.y).abs].max
        end
        
        start = @grid[start_y][start_x]
        finish = @grid[finish_y][finish_x]
        
        visited = Set.new # The set of nodes already evaluated
        previous = {} # Previous node in optimal path from source
        previous[start] = 0
        f_score = PriorityQueue.new
        
        # All possible ways to go in a node
        dx = [1, 1, 0, -1, -1, -1, 0, 1]
        dy = [0, 1, 1, 1, 0, -1, -1, -1]
        
        start.set_g_score(0) # Cost from start along best known path
        f_score[start] = start.g_score + heuristic(start, finish) # Estimated total cost from start to finish
        
        while !f_score.empty?
            current = f_score.delete_min_return_key # Node with smallest f_score
            visited.add(current)
            
            if current == finish
                path = Set.new
                while previous[current]
                    path.add(current)
                    current = previous[current]
                end
                
                print_path(path)
                return "Path found"
            end
            
            # Examine all directions for the next path to take
            for direction in 0..7
                new_x = current.x + dx[direction]
                new_y = current.y + dy[direction]
                
                if new_x < 0 or new_x > @size or new_y < 0 or new_y > @size #Check for out of bounds
                    next # Try next configuration
                end
                
                neighbor = @grid[new_y][new_x]
                
                # Check if we've been to a node or if it is an obstacle
                if visited.include? neighbor or f_score.has_key? neighbor or neighbor.obstacle
                    next
                end
                
                if direction % 2 == 1
                    tentative_g_score = current.g_score + 14 # traveled so far + distance to next node diagonal
                else
                    tentative_g_score = current.g_score + 10 # traveled so far + distance to next node vertical or horizontal
                end
                
                # If there is a new shortest path update our priority queue (relax)
                if tentative_g_score < neighbor.g_score
                    previous[neighbor] =  current
                    neighbor.set_g_score(tentative_g_score)
                    f_score[neighbor] = neighbor.g_score + heuristic(neighbor, finish)
                end
            end
        end
        
        return "Failed to find path"
    end
    
    def print_path(path)
        for y in 0..@size
            for x in 0..@size
                if @grid[y][x].obstacle
                    print "X "
                elsif path.include? @grid[y][x]
                    print "- "
                else
                    print "0 "
                end
            end
            print "\n"
        end
    end
    
    def to_s
        return @grid.inspect
    end
end

g = Graph.new(8)
g.set_obstacle(1,1)
g.set_obstacle(2,2)
g.set_obstacle(3,3)
g.set_obstacle(4,4)
g.set_obstacle(5,5)
g.set_obstacle(6,6)
g.set_obstacle(2,1)
g.set_obstacle(3,2)
g.set_obstacle(4,3)
g.set_obstacle(5,4)
g.set_obstacle(6,5)
puts g.shortest_path(0,2,6,3)

I also created a gist of this implementation so that you can view and play around with the code on Github. Definitely try implementing this in another language or if Ruby is your language of choice try and modify/optimize my implementation. A simple modification would be adjusting the graph and A* function to allow for a rectangular shape. Let me know in the comments what you come up with.

As always if you have any feedback or questions feel free to drop them in the comments below or contact me privately on my contact page. Thanks for reading!

P.S. If your company is looking to hire an awesome soon-to-be college graduate (May 2013) let me know!

Tags: Ruby

Comments:

  • amazing news - 3 months, 2 weeks ago

    Thanks for the nice blog. It was very useful for me. I'm happy I found this blog. Thank you for sharing with us,I too always learn something new from your post.

    reply

  • boom beach hack - 3 months, 1 week ago

    This is such a great resource that you are providing and you give it away for free. I love seeing websites that understand the value of providing a quality resource for free. It is the old what goes around comes around routine.

    reply

  • loft conversions london - 1 month ago

    Fantastic blog you have here. You’ll discover me looking at your stuff often. Saved!

    reply

  • how to get more ig followers - 1 month ago

    Thanks a lot for sharing us about this update. Hope you will not get tired on making posts as informative as this.

    reply

  • buy real instagram comments - 1 month ago

    I admire what you have done here. I like the part where you say you are doing this to give back but I would assume by all the comments that this is working for you as well.

    reply

  • clash of clans hacks - 1 month ago

    I have bookmarked your blog, the articles are way better than other similar blogs.. thanks for a great blog!

    reply

  • jual hajar jahanam - 1 month ago

    pusat dan supplier penjualan hajar jahannam dimana hajar jahannam ini terdiri atas dua produk yaitu hajar jahannam cair dan hajar jahannam batu yang berfungsi untuk memuaskan istri jaminan tahan lama 3 jam di ranjang.

    reply

  • navigate to this web-site - 2 weeks, 6 days ago

    Your blog provided us with valuable information to work with. Each & every tips of your post are awesome. Thanks a lot for sharing. Keep blogging,

    reply

  • ملات فوران - 2 weeks, 3 days ago

    Pretty enlightening posting! There's a simple number of information and facts listed here that can assist every business enterprise get started with a booming social networks marketing!

    reply

  • buy twitter followers - 1 week, 1 day ago

    I recently came across your blog and have been reading along. I thought I would leave my first comment. I don't know what to say except that I have enjoyed reading. Nice blog. I will keep visiting this blog very often.

    reply

  • www.onlinebusiness-solutions.c - 1 week ago

    The web is the present hotspot full of unlimited info in reference different factors of internet business systems.

    reply

  • wallens - 3 months, 1 week ago

    Your music is amazing. <a href='http://hackgames.us/Boom-Beach-Hack/' target='_blank'>boom beach hack</a> You have some very talented artists. I wish you the best of success. <a href='http://hackgames.us/Subway-Surfers-Hack/' target='_blank'>subway surfers cheats</a>

    reply

  • How To Get Him Back - 2 weeks, 5 days ago

    Thanks for your information about the graph theory which will help me in my job.

    reply

  • subway surfers cheats - 3 months, 1 week ago

    If you set out to make me think today; mission accomplished! I really like your writing style and how you express your ideas. Thank you.

    reply

  • How To Get My Ex Back Again - 2 weeks, 4 days ago

    The way how you will express your feeling in front of others.

    reply

  • Get Ex Boyfriend Now - 2 weeks, 2 days ago

    We will check out the graph theory and find the short path of it.

    reply

  • best seo services - 3 months, 1 week ago

    it was a wonderful chance to visit this kind of site and I am happy to know. thank you so much for giving us a chance to have this opportunity..

    reply

  • loft conversions - 2 months ago

    What you presented was well researched and well worded in order to get your stand on this across to all your readers.

    reply

  • Human Resource Outsourcing - 3 weeks, 3 days ago

    Super-Duper site! I am Loving it!! Will come back again, Im taking your feed also, Thanks.

    reply

  • gel insoles - 3 months ago

    I really appreciate the kind of topics you post here. Thanks for sharing us a great information that is actually helpful. Good day!

    reply

  • shadow fight 2 - 3 months ago

    Wow what a Great Information about World Day its very nice informative post. thanks for the post.

    reply

  • summoners war - 3 months ago

    I would like to say that this blog really convinced me to do it! Thanks, very good post.

    reply

  • loft conversion design ideas - 2 months, 3 weeks ago

    Great survey, I'm sure you're getting a great response.

    reply

  • annunci immobiliari monaco - 2 months, 2 weeks ago

    I havent any word to appreciate this post.....Really i am impressed from this post....the person who create this post it was a great human..thanks for shared this with us.

    reply

  • Blog Commenting Service - 1 month ago

    So it is interesting and very good written and see what they think about other people.

    reply

  • Boston Car Service - 1 month ago

    I recommend only good and reliable information, so see it:

    reply

  • www.rebelmouse.com/3weekdietreviews/ - 1 month ago

    Brian Flatt Reveals His Weirdly Effective, Science Based Weight Loss System For Quickly Burning Away 12-23 Lbs Of Stubborn Body Fat In Just 21 Days...

    reply

  • rebuild hair program jared gates ebook review - 1 month ago

    Awesome dispatch! I am indeed getting apt to over this info, is truly neighborly my buddy. Likewise fantastic blog here among many of the costly info you acquire. Reserve up the beneficial process you are doing here.

    reply

  • sapdeal discount coupons - 1 month ago

    Mate, you've shown some really good writing skills here. I knew you had it in you to be a top writer and you've shown that today. Keep this consistent work going!

    reply

  • free hacks cheats and more - 1 month ago

    I have a new way to reach your goal without any need of money than click on these given website to make you feel happy.

    reply

  • jual pc - 1 month ago

    The best article I came across a number of years, write something about it on this page.

    reply

  • Airport taxi Toronto - 4 weeks, 1 day ago

    I might suggest solely beneficial in addition to trusted facts, and so find it:

    reply

  • MY WEBSITE - 4 weeks, 1 day ago

    During this website, you will see this shape, i highly recommend you learn this review.

    reply

  • dirty talking plans for women - 4 weeks, 1 day ago

    Really enjoyed this blog post, can you make it so I receive an email whenever you write a fresh post?

    reply

  • Schlüsselnotdienst Berlin - 4 weeks, 1 day ago

    It’s appropriate time to make some plans for the future and it is time to be happy. I have read this post and if I could I wish to suggest you few interesting things or advice. Perhaps you could write next articles referring to this article. I desire to read even more things about it!

    reply

  • Leora - 4 weeks, 1 day ago

    Thanks for your post. I’ve been thinking about writing a very comparable post over the last couple of weeks, I’ll probably keep it short and sweet and link to this instead if thats cool. Thanks.

    reply

  • buying provigil online - 4 weeks, 1 day ago

    I like all the surveys have been posted by the guests of this site ,some of them are great recommended respect the article.

    reply

  • Marketing 1on1 - 2 weeks, 4 days ago

    I recently came across your blog and have been reading along. I thought I would leave my first comment. I don't know what to say except that I have enjoyed reading. Nice blog. I will keep visiting this blog very often.

    reply

  • f4x led - 4 weeks, 1 day ago

    Should there be another persuasive post you can share next time, I’ll be surely waiting for it.

    reply

  • National university in Vietnam - 4 weeks ago

    hi was just seeing if you minded a comment. i like your website and the thme you picked is super. I will be back.

    reply

  • clash of clans para pc - 4 weeks ago

    Hello I am so delighted I located your blog, I really located you by mistake, while I was watching on google for something else, Anyways I am here now and could just like to say thank for a tremendous post and a all round entertaining website. Please do keep up the great work.

    reply

  • hay day cheats - 4 weeks ago

    I really like your writing style, great information, thankyou for posting.

    reply

  • perfect swiss - 4 weeks ago

    Nice to be visiting your blog once more, it has been months for me. Well this article that ive been waited for therefore long. i want this article to finish my assignment within the faculty, and it has same topic together with your article. Thanks, nice share.

    reply

  • easy healthy dinner recipes - 4 weeks ago

    I understand this column. I realize You put a many of struggle to found this story. I admire your process.

    reply

  • Serenity Rehabilitation - 3 weeks, 6 days ago

    I use only high quality materials - you can see them at:

    reply

  • venus factor diet - 3 weeks, 6 days ago

    It is exceptionally educational. I truly appreciate basically perusing the majority of your weblogs.

    reply

  • backlink buy - 3 weeks, 6 days ago

    Great write-up, I am a big believer in commenting on blogs to inform the blog writers know that they’ve added something worthwhile to the world wide web!..

    reply

  • munich ts escort - 3 weeks, 6 days ago

    Thanks for your post. I’ve been thinking about writing a very comparable post over the last couple of weeks, I’ll probably keep it short and sweet and link to this instead if thats cool. Thanks.

    reply

  • tips to lose weight fast - 3 weeks, 6 days ago

    Thanks for posting this info. I just want to let you know that I just check out your site and I find it very interesting and informative. I can't wait to read lots of your posts.

    reply

  • Loft conversions South London - 3 weeks, 6 days ago

    I wish more authors of this type of content would take the time you did to research and write so well. I am very impressed with your vision and insight.

    reply

  • Modvigil - 3 weeks, 5 days ago

    I like your blog entry. Continue composing this kind of incredible stuff. I'll make a point to catch up on your website later on.

    reply

  • Manual Testing Training in Chennai - 3 weeks, 5 days ago

    Thanks for this article on Graph Theory: Finding The Shortest Path (Part 2) . Very informative.

    reply

  • The Venus Factor - 3 weeks, 1 day ago

    Check out the graph of the theory of the latest show that will help us.

    reply

  • how to get instagram followers - 2 weeks, 4 days ago

    No doubt this is an excellent post I got a lot of knowledge after reading good luck. Theme of blog is excellent there is almost everything to read, Brilliant post.

    reply

  • Good University in Vietnam - 3 weeks, 5 days ago

    Cool you write, the information is very good and interesting, I'll give you a link to my site.

    reply

  • lawrenceville - 3 weeks, 4 days ago

    Within this webpage, you'll see the page, you need to understand this data.

    reply

  • talking soccer - 3 weeks, 4 days ago

    I found this is an informative and interesting post so i think so it is very useful and knowledgeable. I would like to thank you for the efforts you have made in writing this article.

    reply

  • playstation-psn.fr - 3 weeks, 3 days ago

    will be alluding a considerable measure of companions about this.Keep blogging. This is my first time visit here.

    reply

  • buy instagram comments - 2 weeks, 4 days ago

    This is a smart blog. I mean it. You have so much knowledge about this issue, and so much passion. You also know how to make people rally behind it, obviously from the responses.

    reply

  • How to choose best mattress topper - 3 weeks, 2 days ago

    You created few excellent outlooks there.I did a squint for on the text moreover discovered most persons volition blessing accompanying your trap page

    reply

  • Spartagen XT - 3 weeks, 1 day ago

    I have read a few of the articles on your website now, and I really like your style of blogging. I added it to my favorites blog site list and will be checking back soon. Please check out my site as well and let me know what you think.

    reply

  • list academy review - 1 week, 5 days ago

    Your content is nothing short of brilliant in many ways. I think this is engaging and eye-opening material. Thank you so much for caring about your content and your readers.

    reply

  • http://starwintech.com - 3 weeks, 1 day ago

    It is rather very good, nevertheless glance at the data with this handle.

    reply

  • auto title loans Los Angeles CA - 3 weeks, 1 day ago

    I appreciated your work very thanks

    reply

  • dreamiteam.pl - 3 weeks, 1 day ago

    Your blog provided us with valuable information to work with. Each & every tips of your post are awesome. Thanks a lot for sharing. Keep blogging..

    reply

  • Maid Service - 3 weeks ago

    On that website page, you'll see your description, why not read through this.

    reply

  • kaynar wires - 3 weeks ago

    This is very interesting, but it is necessary to click on this link:

    reply

  • loft conversions fulham - 3 weeks ago

    I wanted to thank you for this excellent read!! I definitely loved every little bit of it. I have you bookmarked your site to check out the new stuff you post.

    reply

  • buy duracell batteries - 3 weeks ago

    Keep up the good work , I read few posts on this web site and I conceive that your blog is very interesting and has sets of fantastic information.

    reply

  • no deposit codes - 3 weeks ago

    I wrote about a similar issue, I give you the link to my site.

    reply

  • visita il sito - 3 weeks ago

    For many people this is important, so check out my profile:

    reply

  • network marketing software - 2 weeks, 6 days ago

    Very good topic, similar texts are I do not know if they are as good as your work out.

    reply

  • How To Win Her Back - 2 weeks, 6 days ago

    I can make any type of graph in excel sheet.

    reply

  • HTET Admit Card - 2 weeks, 6 days ago

    This is really a nice and informative, containing all information and also has a great impact on the new technology. Thanks for sharing it

    reply

  • Aico jacob-furniture.com - 2 weeks, 6 days ago

    Thankyou for this wondrous post, I am glad I observed this website on yahoo.

    reply

  • low carb protein powder - 2 weeks, 6 days ago

    Thanks for sharing the info, keep up the good work going.... I really enjoyed exploring your site. good resource...

    reply

  • https://www.rebelmouse.com/venusfactorsystemreview - 2 weeks, 6 days ago

    You should mainly superior together with well-performing material, which means that see it:

    reply

  • "phoenix seo expert" - 2 weeks, 5 days ago

    This is very useful, although it will be important to help simply click that web page link:

    reply

  • New Smart Watches - 2 weeks, 5 days ago

    Here you will learn what is important, it gives you a link to an interesting web page:

    reply

  • agen bola sbobet - 2 weeks, 5 days ago

    Why people love to gamble? it is because they have enough money to bet? or they really love and it is part of their fashion and hobby. Well i don't care why they love the important is it is easy to find a gambling company online and be careful also. <a href="http://cyber-bola.com/">Agen Bola Sbobet</a>

    reply

  • head soccer - 2 weeks ago

    This is a great post. I like this topic.This site has lots of advantage.I found many interesting things from this site. It helps me in many ways.Thanks for posting this again.

    reply

  • turn photo to portrait - 2 weeks, 4 days ago

    At this point you'll find out what is important, it all gives a url to the appealing page:

    reply

  • https://www.rebelmouse.com/crackthegirlcodereviews - 2 weeks, 4 days ago

    Excellent read, Positive site, where did u come up with the information on this posting?I have read a few of the articles on your website now, and I really like your style. Thanks a million and please keep up the effective work.

    reply

  • cell phone signal booster - 2 weeks, 4 days ago

    On this page you can read my interests, write something special.

    reply

  • anunciate gratis - 2 weeks, 4 days ago

    Beaver says I also have such interest, you can read my profile here:

    reply

  • Text Psychic Reading - 2 weeks, 4 days ago

    I really enjoyed reading this post, big fan. Keep up the good work andplease tell me when can you publish more articles or where can I read more on the subject?

    reply

  • hajj packages - 2 weeks, 4 days ago

    Just admiring your work and wondering how you managed this blog so well. It’s so remarkable that I can't afford to not go through this valuable information whenever I surf the internet!

    reply

  • electrical contractors Birmingham - 2 weeks, 4 days ago

    Friend, this web site might be fabolous, i just like it.

    reply

  • Win Your Ex Girlfriend Back - 2 weeks, 2 days ago

    We are the finest part of your graph level.

    reply

  • Patlarny Happy Vagina Principle - 2 weeks, 4 days ago

    An interesting dialogue is price comment. I feel that it is best to write more on this matter, it may not be a taboo topic however usually individuals are not enough to talk on such topics. To the next. Cheers.

    reply

  • paleo grubs - 2 weeks, 3 days ago

    In this case you will begin it is important, it again produces a web site a strong significant internet site:

    reply

  • http://ppihealth.com/ - 2 weeks, 3 days ago

    These websites are really needed, you can learn a lot.

    reply

  • http://lhspress.com/ - 2 weeks, 3 days ago

    It is fine, nonetheless evaluate the information and facts around this correct.

    reply

  • online video marketing - 2 weeks, 3 days ago

    Nice to read your article! I am looking forward to sharing your adventures and experiences.

    reply

  • binary options comparison - 2 weeks, 3 days ago

    Thanks for the blog post buddy! Keep them coming...

    reply

  • How To Get Your Ex Back - 2 weeks, 1 day ago

    I will read this blog in my free time in order to understand each words.

    reply

  • voyance sans attente - 2 weeks, 3 days ago

    I recently came across your blog and have been reading along. I thought I would leave my first comment. I don't know what to say except that I have enjoyed reading. Nice blog. I will keep visiting this blog very often.

    reply

  • femme de ménage Montréal - 2 weeks, 3 days ago

    This is just the information I am finding everywhere. Thanks for your blog, I just subscribe your blog. This is a nice blog..

    reply

  • Aimee Age Correction Cream - 2 weeks, 3 days ago

    Great thought you share.I like it. I will try and check back more often. How frequently you update your website.

    reply

  • MUneer - 2 weeks, 3 days ago

    thanks for the info, very good information <a href="https://plus.google.com/u/0/115576908141303685078/about">https://www.facebook.com/4inkjetscouponcode</a>

    reply

  • https://www.facebook.com/4inkjetscouponcode - 2 weeks, 3 days ago

    First You got a great blog .I will be interested in more similar topics. i see you got really very useful topics, i will be always checking your blog thanks.

    reply

  • Daftar situs terpopuler - 2 weeks, 3 days ago

    need more time to learn about that code, but its very wonderful share.. thanks so much

    reply

  • start potty training in 3 days - 2 weeks, 3 days ago

    You ought to basically fantastic not to mention solid advice, which means notice:

    reply

  • franchise ménage résidentiel - 2 weeks, 2 days ago

    Its a great pleasure reading your post.Its full of information I am looking for and I love to post a comment that "The content of your post is awesome" Great work.

    reply

  • Tarbbatigan Social Plugin Tip - 2 weeks, 2 days ago

    This is a great article thanks for sharing this informative information. I will visit your blog regularly for some latest post. I will visit your blog regularly for Some latest post.

    reply

  • Save The Marriage System - 2 weeks, 1 day ago

    You possess lifted an essential offspring..Blesss for using..I would want to study better latest transactions from this blog..preserve posting..

    reply

  • great health tips - 2 weeks, 1 day ago

    I am additionally constructing new destinations the greater part of the time and getting great results by utilizing regular routines.

    reply

  • learn more - 2 weeks, 1 day ago

    The first mobile bar for rent with newly designed and fully customized mobile bar with LED that suit to everyone let us party bring friends and love ones to enjo

    reply

  • Active Registrar - 2 weeks, 1 day ago

    I basically need to let you know that I am new to weblog and most likely loved this online journal website. Likely I'm going to bookmark your website.

    reply

  • international reverse phone detective - 2 weeks, 1 day ago

    I might suggest solely beneficial in addition to trusted facts, and so find it:

    reply

  • sell diabetic test strips - 2 weeks, 1 day ago

    For many people this is the best solution here see how to do it.

    reply

  • live pr submitter - 2 weeks ago

    Your content is nothing short of brilliant in many ways. I think this is engaging and eye-opening material. Thank you so much for caring about your content and your readers.

    reply

  • Schallingora Success Key Scheme - 2 weeks ago

    I’ve been surfing online more than three hours today, yet I never found any interesting article like yours. It’s pretty worth enough for me. In my opinion, if all webmasters and bloggers made good content as you did, the web will be a lot more useful than ever before.

    reply

  • https://www.youtube.com/watch?v=P1t13ru_DMo/ - 2 weeks ago

    I would like to thank you for the efforts you have made in writing this article. I am hoping the same best work from you in the future as well. Thanks...

    reply

  • compro oro - 2 weeks ago

    Likewise extraordinary blog here with the greater part of the important data you have. Keep doing awesome doing here.

    reply

  • the respect principle guide - 1 week, 6 days ago

    Listed here you'll learn it is important, them offers the link in an helpful webpage:

    reply

  • 12v 7ah battery - 6 days, 14 hours ago

    Thanks for the post and great tips..even I also think that hard work is the most important aspect of getting success..

    reply

  • http://www.beaconcom.sg/lead-generation/seo/ - 1 week, 6 days ago

    This is likewise a decent post which I truly appreciated perusing. It is not regular that I have the likelihood to see something like this.

    reply

  • terravita homes for sale az - 1 week, 6 days ago

    Very interesting information, worth recommending. However, I recommend this:

    reply

  • buy arabic twitter followers - 1 week, 5 days ago

    I can see that you are an expert at your field! I am launching a website soon, and your information will be very useful for me.. Thanks for all your help and wishing you all the success in your business.

    reply

  • 12 week rapid fat loss plan for women - 1 week, 5 days ago

    I gotta favorite this website it seems very helpful .

    reply

  • Good University in Vietnam - 1 week, 5 days ago

    Pretty good post. I just stumbled upon your blog and wanted to say that I have really enjoyed reading your blog posts. Any way I'll be subscribing to your feed and I hope you post again soon. Big thanks for the useful info.

    reply

  • Language of desire pdf - 1 week, 5 days ago

    It is fine, nonetheless evaluate the information and facts around this correct.

    reply

  • how to deal with obesity and enhance fat burning - 1 week, 3 days ago

    E-Factor Diet Review: Facts And Figures Every Consumer Should Know About John Rowley's Guide to Increase Your Fat Burning Hormones. Below you will find the important facts and figures I feel every consumer should know surrounding John Rowley's E-Factor Diet book and complete guide for taking necessary precautions and improve weight loss simultaneously.

    reply

  • coffee grinder - 1 week, 3 days ago

    This could be one of the best pieces I have had for quite a while. I will absolutely return. You totally duplication our mean and the distinction of our data.

    reply

  • Capture His Heart PDF - 1 week, 2 days ago

    On this subject internet page, you'll see my best information, be sure to look over this level of detail.

    reply

  • Ancient secrets of kings - 1 week, 2 days ago

    Here you will learn what is important, it gives you a link to an interesting web page:

    reply

  • Bring The Fresh Review - 1 week, 1 day ago

    Wonderful blog! I found it while surfing around on Yahoo News. Do you have any suggestions on how to get listed in Yahoo News? I’ve been trying for a while but I never seem to get there! Appreciate it.

    reply

  • removing mold - 1 week, 1 day ago

    At this point you'll find out what is important, it all gives a url to the appealing page:

    reply

  • Jual Printer - 1 week, 1 day ago

    So lot to occur over your amazing blog. Your blog procures me a fantastic transaction of enjoyable.. Salubrious lot beside the scene.

    reply

  • What to get your boyfriend for his birthday ? - 1 week ago

    I wrote about a similar issue, I give you the link to my site.

    reply

  • brand activation companies - 1 week ago

    Forza Migliozzi is an award winning advertising agency that successfully defies conventional methods to create and discover new approaches to reach your consumer. From brand activation to experiential to traditional, Forza Migliozzi is a full service advertising and brand content agency.

    reply

  • http://sandiego.locanto.com/ID_512085159/Orange-Re - 1 week ago

    A very awesome blog post. We are really grateful for your blog post. You will find a lot of approaches after visiting your post. I was exactly searching for. Thanks for such post and please keep it up. Great work.

    reply

  • voyance retour amour - 1 week ago

    That was a fantastic consideration of this case! I like very much to read Your posts and this is for me absolutely number one blog in this topic! Congratulations and keep working like this.

    reply

  • loft conversions london - 1 week ago

    This is a good post. This post gives truly quality information. I’m definitely going to look into it. Really very useful tips are provided here. Thank you so much. Keep up the good works.

    reply

  • Why I Used Smoking Bob's BBQ Tips - 1 week ago

    It's superior, however , check out material at the street address.

    reply

  • http://clearlytalking.com/seven-secrets-for- - 1 week ago

    In current times there has been a contraction in the Insurance coverage market within this sector.

    reply

  • https://rebelmouse.com - 1 week ago

    I've proper selected to build a blog, which I hold been deficient to do for a during. Acknowledges for this inform, it's really serviceable!

    reply

  • Hwa - 1 week ago

    In much less compared to five minutes, customers can contrast over of 100 brand names in a cross-section of the economic markets.

    reply

  • http://detra.pl/detrank/index.php?a=stats&u= - 1 week ago

    In current times there has been a contraction in the Insurance policy market within this industry.

    reply

  • http://www.gamerstvspot.com/video/cvT_ObeSr50/ - 1 week ago

    Riscx Motor Trade Insurance coverage Comparison offer heavily within the investors industry.

    reply

  • http://gallery.snoopyclick.com/educational/ - 1 week ago

    Companies Liability Insurance - Once again a lawful demand when you have any workers or labour just sub service providers.

    reply

  • http://sonicsoultattoo.de/front_single/gb/ - 6 days, 23 hours ago

    If you are at fault for the occurrence, you no claim incentive will certainly be impacted unless you have secure them with a safeguarded no claims plan.

    reply

  • http://supplementwarehousesource.com/wordpress/ - 6 days, 22 hours ago

    A statement by Havana states the Cuban side supplied the U.S.

    delegation information regarding the nation's computer systems as well as cybersecurity plan.

    reply

  • http://www.ambryequipment.com/index.php/blog-page/ - 6 days, 22 hours ago

    If the older policy owner is particularly designated to drive these cars, it is probably much more expense reliable.

    reply

  • hdmovies000.com - 6 days, 21 hours ago

    It was a specifying minute in the American dispute and forced Bush to regulate co2 pollution from motor vehicles under the Clean Air Act.

    reply

  • http://wallpapers.etutsgroup.com/profile/ - 6 days, 20 hours ago

    Whether you have a road risks electric motor field insurance coverage or a traders integrated plan, contacting us to make a modification is simple.

    reply

  • traders insurance online payment - 6 days, 19 hours ago

    Well Dunn Insurance Revolution Services is a trading good name of Well Dunn Limited.

    reply

  • http://bigbeat.bbuoy.com/blog/51-witamy-na-naszej- - 6 days, 18 hours ago

    I've been surfing online more than 3 hrs today, yet I never ever found any sort of fascinating article like your own.

    reply

  • xtreme fat loss diet review - 6 days, 17 hours ago

    This is really cool tutorial about finding shortest path. I love it.

    reply

  • wandervale sim lian - 6 days, 11 hours ago

    In this article understand the most important thing, the item will give you a keyword rich link a great useful website page:

    reply

  • car title loan in Los Angeles - 6 days, 10 hours ago

    Very useful post. This is my first time i visit here. I found so many interesting stuff in your blog especially its discussion. Really its great article. Keep it up.

    reply

  • He’s Not That Complicated PDF - 6 days, 7 hours ago

    On this subject internet page, you'll see my best information, be sure to look over this level of detail.

    reply

  • Lukas - 6 days, 4 hours ago

    I have actually been surfing online more than 3 hrs today, yet I never discovered any kind of fascinating post like your own.

    reply

  • Josie - 6 days, 2 hours ago

    Way cool! Some very valid points! I appreciate you writing this write-up and the rest of the site is also really good.

    reply

  • tinnitus miracle (tm) - 5 days, 12 hours ago

    It was wondering if I could use this write-up on my other website, I will link it back to your website though.Great Thanks.

    reply

  • instant unsecured loans - 5 days, 9 hours ago

    My spouse and I stumbled over here rom a different web page and thought I might as well check thongs out. I like what I see soo now i am following you. Look forward to looking at yoour web page for a second time.

    reply

  • vyriski rubai - 5 days, 7 hours ago

    What's up, its good piece of writing on the topic of media print, we all understand media is a enormous source of facts.

    reply

  • Jaman - 5 days, 6 hours ago

    This information is very useful and innovative, thanks for posting.

    reply

  • Meenakshi - 5 days, 6 hours ago

    Great Post thanks a lot..

    reply

  • Madhan - 5 days, 6 hours ago

    Way cool! Some very valid points! I appreciate you writing this write-up and the rest of the site is also really good

    reply

  • rebuild hair program - 4 days, 17 hours ago

    Great explanation now all doubts of Graph theory is disappear

    reply

  • loft conversions london - 4 days, 12 hours ago

    Great! It sounds good. Thanks for sharing..

    reply

  • green smart living - 4 days, 7 hours ago

    Such intelligent work on the subject and ideal way of writing here. I am really impressed! This post is a helpful overview of the particular topic and very actionable. Interesting approach!

    reply

  • language of desire guide - 3 days, 16 hours ago

    Graph Theory is very well explained in this post. I think no one have question about Graph Theory after reading this post.

    reply

  • PioneerSEO - 3 days, 12 hours ago

    This article is such a nice and interesting one, I'm very satisfied with the provided contents. I hope more excellent articles would be posted in your website. Thank you so much for this and keep sharing.<a href="https://www.webiihost.com/">hosting murah</a>

    reply

  • that's not how men work - 3 days, 8 hours ago

    This content is simply exciting and creative. I have been deciding on a institutional move and this has helped me with one aspect.

    reply

  • smoke recipes - 3 days, 1 hour ago

    I exploit solely premium quality products -- you will observe these individuals on:

    reply

  • http://girlfriendactivationsystemreview.org/ - 2 days, 15 hours ago

    Excellently written article, doubts all bloggers offered the identical content since you, the internet has to be far better place. Please stay the best!.

    reply

  • iklan baris - 2 days, 8 hours ago

    I just got to this amazing site not long ago. I was actually captured with the piece of resources you have got here. Big thumbs up for making such wonderful blog page

    reply

  • venus factor pdf - 2 days, 5 hours ago

    On my website you'll see similar texts, write what you think.

    reply

  • Investment fraud lawyer - 2 days ago

    Once I thought about things like: why such information is for free here? Because when you write a book then at least on selling a book you get a percentage. Thank you and good luck on informing people more about it!

    reply

  • File Xarelto Lawsuit - 2 days ago

    This is a wonderful article, Given so much info in it, These type of articles keeps the users interest in the website, and keep on sharing more ... good luck.

    reply

  • edmonton vet clinics - 1 day, 18 hours ago

    The leading animal hospital in Edmonton now open to serve you with high tech facilities that will take care your animals. So what are you waiting for come and we are open to serve you.

    reply

  • agen sbobet - 1 day, 16 hours ago

    After looking into a few of the blog posts on your web page, I truly like your technique of writing a blog. I saved as a favorite it to my bookmark website list and will be checking back soon. Please visit my website as well and tell me what you think.<a href="http://cyber-bola.com/">Agen Sbobet</a>

    reply

  • احبار - 1 day, 11 hours ago

    For many people this is important, so check out my profile:

    reply

  • water damage repair for property managers - 1 day, 9 hours ago

    This is really a nice and informative, containing all information and also has a great impact on the new technology. Thanks for sharing it.

    reply

  • www.rebelmouse.com - 1 day, 6 hours ago

    This is a great inspiring article.I am pretty much pleased with your good work.You put really very helpful information. Keep it up. Keep blogging. Looking to reading your next post.

    reply

  • Love Traction Lines Free Download - 8 hours ago

    wow this saintly however ,I love your enter plus nice pics might be part personss negative love being defrent mind total poeple ,

    reply

  • Love Traction Lines Free Download - 6 hours ago

    I use only high quality materials - you can see them at:

    reply

  • Wordpress Handleiding - 4 hours ago

    It's superior, however , check out material at the street address.

    reply