Showing posts with label recursion. Show all posts
Showing posts with label recursion. Show all posts

Sunday, February 20, 2011

Prim's Algorithm

Greetings

Sometime back, I wanted to dive into a programming topic called graph theory. Graph theory is an extremely interesting topic in the sense one needs to use their brains to solve graph problems. Also many problems, such as the traveling salesman problem have only been partially solved at yet, making it a NP hard problem. I decided to start my dive with a lesson in Prim's Algorithm. However after countless hours of scourging the web, I could not find the code, nor an explanation simple enough for me to understand the algorithm. Thanks an awesome video I found on YouTube(I don't have the link, but I find it, I will post it here) on the Prim's Algorithm I was able to write my own interpretation of the Algorithm. This code makes use of arrays and simple vectors and is extremely easy to understand. I though of posting this code because I wanted anybody else in my position to be able to understand Prim's algorithm without having to resort to complex, unnecessary code. So what is the Prim' algorithm? Ever heard of problems such as the length of road required to connect all cities? or the cabling needed to form a network of computers, but some computers acting as proxies for the others? Well for all these problems, the MST or the minimum spanning tree has to be found. Imagine a group of cities (A to E) to be the nodes in a graph. Now imagine the distance between them to be the edges in a graph. Here is a pic.
An Example Graph
So the DIRECT distance from A to B is 10, A to E is 34, etc. However what is the least length of road to be constructed so that all the cities are connected? It is certainly not 106, the sum of all the distances. It happens to be 22 or the MST of the graph of cities. Try it out. cross out the distances of 33, 34 and 17 and you should still be able to travel from any city to any other city! Solving such problems require MST which can be found using the Prim's algorithm.The code I release for Prim's algorithm will have a detailed explanation on how it works. Here is a gist: start from any node, mark it visited. Choose the shortest path from all paths available and the add the path length to your MST counter. Get the node at the other end of the chosen path and mark that visited as well. Now considering the paths from all visited nodes, choose the shortest path and mark the node on the other end as visited. Continue to do this until all nodes are visited and once done you have the MST! The Prim's algorithm is great for finding the MST, although a little bit slower than other algorithms. However it is a simple algorithm to learn and is fun to work with. Links for the code and explanation down below. Once again you are free to modify and distribute the code with proper credit given.

Link to .exe file.
Link to code.

This is not the end...

Aravind Rao

Wednesday, February 9, 2011

Intelligent Code

Greetings

Every problem in Computer Science can be solved by accounting for every possible permutation that the program might encounter. Naturally this is not an efficient practice, especially when  the number of possibilities can grow exponentially, reaching billions in no time. To effectively solve such problems, we need to implement  a kind of logic, based on our own thinking while problem solving. This inherent 'common sense' of humans can help create powerful algorithms to solve computer problems, without the aid of brute force. An example of such a problem is a computer game (Source .cpp, and .exe), where a computer tries to guess a users' choice within a given range. If the users' choice is >= the computers' guess, the user inputs 0. If the user's choice is < than the computer;s guess, the user inputs 1. Naturally, the computer can iterate through all numbers in the range from lowest to highest and check whether the computers' guess matches the users' choice and arrive upon the answer when the user inputs one(the users' choice will be the current computers' guess - 1). However what if the range extended from 1 to 2^10? Does it make sense to loop through all those numbers, check for user input and output the answer? This method is not time or user friendly. However, if we implement an algorithm that imitates the way we think when solving such a problem, we can arrive upon an extremely efficient solution for this problem. Consider the range 0 to 16. The user's choice is 11. Now lets add 1 to 0 and 1 to 16, to make the range 1-17. This is done because we will than have 2 nice halves of the range: 1-8 and 9-17. This idea of dividing the range into half will be central to out algorithm. You will get why I do this later. Now the computer has 1\16 or 6.25 % chance of guessing the right user's choice. If it iterated through all the values of the range and checked it against the user input, the probability of the program guessing the right choice will be increased to 6.67% -> 7.14 %...etc.(Not really, but for the time being, let us consider the case to be true). What should the program do to arrive upon the answer faster and in fewer tries? It should try to increase the probability of getting the right answer in each successful turn by a greater rate. For example in the range 1-17, the computer programs' first guess has to be (1+17)/2 = 9 or the average of the range extremes. Why? Because if the user inputs 1, the users' guess is less than 9, so it is in the range 1-8. Alternatively, if the user inputs 0, the users' guess will be greater than or equal to 9, and thus in the range 9-16. What have we achieved here? We have increased them probability of the computer guessing the right answer in the next turn to a whooping (1/8)% = 12.5%, which is the double the probability of guessing the right answer of the programs' first turn. Compare this with the 6.67% probability while iterating through all values!Now since the user's choice is 11, he will input 0, and now the computer program will carry out the same operation, although this time on a different range, that is 9-16. After this turn, the probability of guessing the answer right will increase to 25%, then to 50% and finally to 100% When it reaches 1000%, the program will have the answer! his method only works on ranges whose higher extreme can be expressed as:
Log2(Higher Extreme) = some Natural Number.
Therefore 16 works(log2(16) = 4), so does 8. 32 and 4096. The number of guesses the program will make is log2(higher Extreme). In the case of the higher Extreme being 16, the program will make 4 guesses, in the case of 32, it will make 5 guesses and so on.
I have provided the links to the source code and .exe file of this 'game'. Feel free to edit it, distribute it and use it, although with proper credit!

Link to .cpp source file.
Link to .exe playable game file.


This is not the end

Aravind Rao

Thursday, November 25, 2010

Day of the Knight

Recursion n. See recursion
Search v. Definition hidden at the end

Greetings
I am came across an interesting problem sometime back on the net. The problem in a nutshell was to calculate the least of amount of steps that it would take a knight to get from square(a,b) to square(x,y). The real task at hand was to map out the whole chessboard, with values denoting the depth or breadth level from the starting square. This question could be solved two ways, using either the Depth First Search Method, or the Breadth First Search Method. I am going to speak about them in this post.
DEPTH FIRST SEARCH:

The Depth First Search or DFS is a recursive searching method, where by, on goes down as long as they can until they hit a dead end. When they do, they go one up, and starting going down again, although this time in a different path. Consider it like this. Imagine a house full of rooms. Inside these rooms there are more rooms, inside which there are even more. Your task is to find how many rooms one has to go through to get to room 8. Diagram given below.
The room location map.

In a typical DFS search, the longest search order would be something like this:
Start->1->4(Dead End!)->1->5->9->5->1->Start->2->6->10->6->11->6->2->Start->3->7->12->7->3->8

In a typical DFS search, the shortest search order would be something like this:
Start->3->8
      ...............and many possible permutations in between.

As you can see, something that is just two levels away from the start takes a maximum of 23 node visits, where as the shortest one takes just 3 node visits. There is no way to ensure the DFS method to make the shortest node visits, as the DFS wont know the location of the node in absolute terms, only in relationship to other nodes. In part, the DFS has such a high, unacceptable worst case scenario result is because many of the nodes are re-visited many times over.(Start, 1, 5, etc). The difference between the best and worst cases is way too big for the search to be efficient.

BREADTH FIRST SEARCH

The search technique in BFS involves grouping nodes with the same absolute distance nodal distance from Start Point in the same breadth. Imagine that after the BFS technique identifies the nodes with nodal distance 1 from the start point. All these nodes are in Breadth Level 1. These nodes will then be pushed into a stack, where EACH on of these nodes will become the Start Point. Now the nodes with a nodal distance of 1 from these Start points will be grouped in Breadth Level 1 more than than the breadth level of their starting points, something like (Node Level = Start Point Level + 1). In this manner all the nodes will be mapped and assigned a value denoting their absolute nodal distance from the first Start Point. Here is a diagram.

The room Location Map, now with Breadth levels.

In a typical BFS search the search order would be something like this:
Start->1,2,3 stack.push(1,2,3)-1st Level
loop through stack as long as there are nodes.
1->4,5 stack.pop(1) stack.push(4,5)-2nd Level
2->6 stack.pop(2) stack.push(6)-2nd Level
3->7,8 stack.pop(3) stack.push(7,8)-2nd Level //Stop here, 8 is found
4->Dead End! stack.pop(4)-3rd Level
5->9 stack.pop(5) stack.push(9)-3rd Level
6->10,11 stack.pop(6) stack.push(10,11)-3rd Level
7->12 stack.pop(7) stack.push(12)-3rd Level
8->Dead End! stack.pop(8) -3rd Level
9->Dead End! stack.pop(9) -4th Level
10->Dead End! stack.pop(10) -4th Level
11->Dead End! stack.pop(11) -4th Level
12->Dead End! stack.pop(12) -4th Level

Another, faster case
Start->3,2,1 stack.push(3,2,1)-1st Level
loop through stack.
3->7,8 stack.pop(3) stack.push(7,8)-2nd Level //Stop here, 8 is found

As you can see, each node is not visited more than once, only its location is pushed into the stack. After its immediate nodes are visited, it should be popped out or removed, otherwise you will have an infinite loop.
The difference between the best and worst case scenarios is not much, and is generally more efficient than DFS, as it takes less time, resources and searched intuitively.

The C++ program that I built also uses the same technique of BFS to solve the problem. Have a look at it, annotations are included and post your feedback or questions regarding the program.
Link for the .cpp File
Link for the .exe File

 Until the NXT post

Aravind Rao, chief Hacker(claimed)