310 likes | 495 Views
Tirgul no. 8. Topics covered : Recursion: Fibonacci Factorial, GCD Backtracking – N-Queens and Knight moves. Fibonacci (1202). Adapted from : http://www.mcs.surrey.ac.uk/Personal/R.Knott/Fibonacci/fibnat.html
E N D
Tirgul no. 8 Topics covered: • Recursion: • Fibonacci • Factorial, GCD • Backtracking – N-Queens and Knight moves
Fibonacci (1202) Adapted from : http://www.mcs.surrey.ac.uk/Personal/R.Knott/Fibonacci/fibnat.html The original problem that Fibonacci investigated (in the year 1202) was about how fast rabbits could breed in ideal circumstances. Problem: Suppose a newly-born pair of rabbits, one male, one female, are put in a field. Rabbits are able to mate at the age of one month so that at the end of its second month a female can produce another pair of rabbits. Suppose that our rabbits never die and that the female always produces one new pair (one male, one female) every month from the second month on. The puzzle that Fibonacci posed was... Question: How many pairs will there be in one year?
Fibonacci Answer: • At the end of the first month, they mate, but there is still one only 1 pair. • At the end of the second month the female produces a new pair, so now there are 2 pairs of rabbits in the field. • At the end of the third month, the original female produces a second pair, making 3 pairs in all in the field. • At the end of the fourth month, the original female has produced yet another new pair, the female born two months ago produces her first pair also, making 5 pairs.
Fibonacci The Rabbits problem is not very realistic! 1) It seems to imply that brother and sisters mate, which, genetically, leads to problems. We can get round this by saying that the female of each pair mates with any male and produces another pair. 2) Another problem which again is not true to life, is that each birth is of exactly two rabbits, one male and one female. Let’s look at HoneyBees – for a more realistic example!
Fibonacci – HoneyBees! • In a colony of honeybees there is one special female called the queen. • There are many worker bees who are female too but unlike the queen bee, they produce no eggs. • There are some drone bees who are male and do no work. Males are produced by the queen's unfertilized eggs, so male bees only have a mother but no father! • All the females are produced when the queen has mated with a male and so have two parents. Females usually end up as worker bees but some are fed with a special substance called royal jelly which makes them grow into queens ready to go off to start a new colony when the bees form a swarm and leave their home (a hive) in search of a place to build a new nest.
Fibonacci – HoneyBees! (cont.) So female bees have 2 parents, a male and a female whereas male bees have just one parent, a female. Let’s look at a family tree of a male drone!
Fibonacci – HoneyBees! (cont.) • He had 1 parent, a female. • He has 2 grand-parents, since his mother had two parents, a male and a female. • He has 3 great-grand-parents: his grand-mother had two parents but his grand-father had only one. • How many great-great-grand parents did he have?
Fibonacy Rectangles and Shell Spirals • We can make another picture showing the Fibonacci numbers 1,1,2,3,5,8,13,21,.. if we start with two small squares of size 1 next to each other. On top of both of these draw a square of size 2 (=1+1) and so on.
Fibonacy Rectangles and Shell Spirals • If we now draw quarter circles in each of the rectangles: • This is a spiral (the Fibonacci Spiral). • A similar curve to this occurs in nature as the shape of a snail shell or some sea shells
Fibonacy Spirals: Seed Heads • Fibonacci numbers can also be seen in the arrangement of seeds on flower heads • The picture here is a beautiful photograph of a Coneflower:
Fibonacy Spirals: Seed Heads • Let’s look from the top: • The same happens in many seed and flower heads in nature. The reason seems to be that this arrangement forms an optimal packing of the seeds so that, no matter how large the seed head, they are uniformly packed at any stage, all the seeds being the same size, no crowding in the centre and not too sparse at the edges.
Fibonacci – Java Code! The Fibonacci series is defined as : Fibonacci(1) = 1 Fibonacci(2) =1 Fibonacci(n) = Fibonacci(n-1) + Fibonacci(n-2) Java implementation: /** * This method makes Fibonacci(n)-1 additions , not the best * way to go. */ public int recursiveFibonacci(int n) { if ((n == 1) || (n == 2)) return 1; else return(recursiveFibonacci(n-1) + recursiveFibonacci(n-2)); }
Fibonacci Improvement no. 1: Iterative solution: /** * This method makes n-1 additions. */ public int iterativeFibonacci(int n) { int prev,cur,tmp; prev = 0; cur = 1; for(int i = 1; i< n ; i++) { tmp = prev + cur; prev = cur; cur = tmp; } return cur; }
Fibonacci Improvement no. 2: closed form solution Compute the fibonacci number explicitly according to Binet’s formula: public int explicitFibonacci(int n) { double sqrtFive = Math.sqrt(5); return(int) ((1/sqrtFive)*Math.pow(((1+sqrtFive)/2),n) - (1/sqrtFive)*Math.pow(((1-sqrtFive)/2),n)); }
Factorial /** * Computes the factorial of a number. * @param n The given number. * @return n! - The factorial of n. */ public static long factorial(long n) { long multiplication = 1; for (int i=1; i<n; i++) { multiplication *= i; } return multiplication; } /** * Computes the factorial of a number. * @param n A positive integer. * @return n! - The factorial of n. */ public static long factorial(long n) { if (n==1) { return 1; } return n*factorial(n-1); }
Gcd (Greatest Common Divisor) /** * Method for computing the greatest common divisor of two numbers. * gcd(y,x) if(y>x) * gcd(x,y) = x if(y==0) * gcd(y, x % y) if x>0 */ public int gcd(int x , int y) { int xAbs = Math.abs(x); int yAbs = Math.abs(y); if(xAbs<yAbs) return gcd(yAbs,xAbs); else if(yAbs == 0) return xAbs; else return gcd(yAbs,xAbs % yAbs); }
Binary Search (recursive) /** * recursive binary search. */ public boolean find(int data[],int num,int low,int high) { int mid = (low+high)/2 ; if(data[mid] == num) return true; else if((data[mid] > num) && (low<mid)) return find(data,num,low,mid-1); else if((data[mid] < num) && (high>mid)) return find(data,num,mid+1,high); //number isn't in the array return false; }
Polynom class /** * This class represents polynoms. * The polynoms are repersented by an array of their coefficients. * Pn(X) = A0*Xn+A1*Xn-1+......+An-1*X+An */ public class Polynom { private double coeff[]; /** * The constructor for a polynom. * @param an array of coefficients. */ public Polynom(double coeff[]) { this.coeff = new double[coeff.length]; System.arraycopy(coeff,0,this.coeff,0,coeff.length); } public double evaluateAt(double x) { return computeVal(x,coeff.length-1); }
Polynom cont. /** * Compute Pn(X) at x recursivly. * Pn(X) = An+x(An-1 + x(An-2....+x(A1+xA0))).....)) */ private double computeVal(double x,int deg) { if(deg == 0) return coeff[0]; else return x*computeVal(x,deg-1) + coeff[deg]; }
Recursion With Backtracking General Scheme recursiveMethod(DataType data,....) { if(end-condition) do-something; else { loop over all options { do something to the data; recursiveMethod(updated-data,....); undo what was done to the data; } } }
The N Queens problem Problem: Place N queens on an NxN board so that no queen threatens another. Solution: Use recursion and backtracking in order to exhaustively search for solutions.
QueensBoard class public class QueensBoard { private boolean board[][]; public QueensBoard(int size) { board = new boolean[size][size]; //board automatically initialized to false } public QueensBoard(QueensBoard original) { int size = original.getSize(); board = new boolean[size][size]; for(int i=0 ; i<size ; i++) System.arraycopy(original.board[i],0,board[i],0,size); } public int getSize() { return board.length; }
QueensBoard class (cont) public String toString() { StringBuffer res = new StringBuffer("*****************\n"); int size = getSize(); for(int row=0 ; row<size ; row++) { for(int col=0 ; col<size ; col++) { if(board[row][col]) res.append('X'); else res.append('O'); res.append('\t'); } res.append('\n'); } res.append("*****************\n"); return res.toString(); } } public boolean isOccupied(int row,int col) { return board[row][col] == true; } public void setQueen(int row,int col) { board[row][col] = true; } public void removeQueen(int row,int col){ board[row][col] = false; }
PlaceQueens class public class PlaceQueens { private QueensBoard board; private boolean hasSolution; public PlaceQueens(int boardSize) { board = new QueensBoard(boardSize); hasSolution = false; }
PlaceQueens class (cont) public void solveBoard() { solve(board,0); if(!_hasSolution) System.out.println("There is no solution for board of size " + board.getSize()+"x"+board.getSize()); } private void solve(QueensBoard board , int col) { if(col == board.getSize()) { System.out.print(board); hasSolution = true; return; } for(int i=0 ; i<board.getSize() ; i++) { if(validPlacing(board,i,col)) { board.setQueen(i,col); solve(board,col+1); board.removeQueen(i,col); } } }
PlaceQueens class (cont) private boolean validPlacing(QueensBoard board,int row, int col) { int i,j; //check there isn't a queen in this row for(i=col-1 ; i>=0 ; i--) { if(board.isOccupied(row,i)) return false; } //check the diagonals for(i=col-1, j=row-1 ; i>=0 && j>=0 ; i--,j--) { if(board.isOccupied(j,i)) return false; } for(i=col-1, j=row+1 ; i>=0 && j<_board.getSize() ; i--,j++) { if(board.isOccupied(j,i)) return false; } //if we got here then there is no queen on the diagonals or the row return true; }
Knight Moves Problem: Starting at the lower-left corner, travel with a knight over all the chess board, without returning twice to the same place
Knight Moves - The Solution public class KnightMoves { private int[][] board; private int size; private static final int[][] MOVES= {{1,2},{1,-2},{-1,2},{-1,-2}, {2,1},{-2,1},{2,-1},{-2,-1}}; methods on next slides... }
KnightMoves - constructor public KnightMoves(int size) { int i,j; size = size; board = new int[size+4][size+4]; for(i=0; i<2; i++) { for(j=0; j < board.length; j++) board[i][j] = -1; } for(i= board.length-2; i < board.length; i++) { for(j=0; j < board.length; j++) board[i][j] = -1; } for(i=2; i < board.length-2; i++) { for(j=0; j<2; j++) board[i][j] = -1; } for(i=2; i < board.length-2; i++) { for(j=board.length-2; j< board.length; j++) board[i][j] = -1; } }
KnightMoves - The Actual Work private boolean solveBoard(int row, int col, int steps) { int newRow, newCol,movesDone; if( board[row][col] != 0 ) //already been here return(false); board[row][col] = steps; if(steps == size*size) //traversed all the board return(true); for(movesDone=0; movesDone < MOVES.length; movesDone++) { newRow = row + MOVES[movesDone][0]; newCol = col + MOVES[movesDone][1]; if(solve(newRow,newCol,steps+1)) return(true); } board[row][col] = 0; return(false); } public boolean solve() { //start the recursive solving - skip the border return(solve(2,2,1)); }