Design and Analysis of Algorithms Laboratory
Design and Analysis of Algorithms Laboratory
1
IV. COURSE CONTENT:
Note: Students are encouraged to bring their own laptops for laboratory
practice sessions.
Using implicit recursion find the second-largest elements from the array.
In this case, the find second largest method calls the find_largest() function via implicit recursion to locate
the second-largest number in a provided list of numbers. Implicit recursion can be used in this way to get
the second-largest integer without having to write any more code
Input: nums = [1, 2, 3, 4, 5]
Output: 4
class IR {
// Function call
int secondLargest = findSecondLargest(numbers);
System.out.println(secondLargest);
}
}
2
1.2 Towers of Hanoi
Tower of Hanoi is a mathematical puzzle where we have three rods (A, B, and C) and N disks. Initially, all the
disks are stacked in decreasing value of diameter i.e., the smallest disk is placed on the top and they are on
rod A. The objective of the puzzle is to move the entire stack to another rod (here considered C), obeying
the following simple rules:
• Only one disk can be moved at a time.
• Each move consists of taking the upper disk from one of the stacks and placing it on top of another
stack i.e. a disk can only be moved if it is the uppermost disk on a stack.
• No disk may be placed on top of a smaller disk.
Input: 2
Output: Disk 1 moved from A to B
Disk 2 moved from A to C
Disk 1 moved from B to C
Input: 3
Output: Disk 1 moved from A to C
Disk 2 moved from A to B
Disk 1 moved from C to B
Disk 3 moved from A to C
Disk 1 moved from B to A
Disk 2 moved from B to C
Disk 1 moved from A to C
Tower of Hanoi using Recursion:
The idea is to use the helper node to reach the destination using recursion. Below is the pattern for this
problem:
• Shift ‘N-1’ disks from ‘A’ to ‘B’, using C.
• Shift last disk from ‘A’ to ‘C’.
• Shift ‘N-1’ disks from ‘B’ to ‘C’, using A.
Follow the steps below to solve the problem:
• Create a function towerOfHanoi where pass the N (current number of disk), from_rod, to_rod,
aux_rod.
• Make a function call for N – 1 th disk.
• Then print the current the disk along with from_rod and to_rod
• Again make a function call for N – 1 th disk.
3
// Recursive java function to solve Tower of Hanoi
class TOH {
static void towerOfHanoi(int n, char from_rod,
char to_rod, char aux_rod)
{
if (n == 0) {
return;
}
// Write code here
…
}
//Driver code
4
• The string “azzy” contains duplicates
• So it is further reduced to “ay”
Input: “caaabbbaacdddd”
Output: Empty String
Input: “acaaabbbacdddd”
Output: “acac”
Procedure to remove duplicates:
• Start from the leftmost character and remove duplicates at left corner if there are any.
• The first character must be different from its adjacent now. Recur for string of length n-1 (string
without first character).
• Let the string obtained after reducing right substring of length n-1 be rem_str. There are three
possible cases
➢ If first character of rem_str matches with the first character of original string, remove the first
character from rem_str.
➢ If remaining string becomes empty and last removed character is same as first character of
original string. Return empty string.
➢ Else, append the first character of the original string at the beginning of rem_str.
• Return rem_str.
class RD {
// If length of string is 1 or 0
if (str.length() == 0 || str.length() == 1)
return str;
5
}
// Driver code
public static void main(String args[])
{
}
}
An algorithm that uses random numbers to decide what to do next anywhere in its logic is called
Randomized Algorithm
Given a deck of cards, the task is to shuffle them
Output:
29 27 20 23 26 21 35 51 15 18 46 32 33 19
24 30 3 45 40 34 16 11 36 50 17 10 7 5 4
39 6 47 38 28 13 44 49 1 8 42 43 48 0 12
37 41 25 2 31 14 22
Output will be different each time because of the random function used in the program
Procedure
1. First, fill the array with the values in order.
2. Go through the array and exchange each element with the randomly chosen element in the range
6
from itself to the end.
// It is possible that an element will be swap
// with itself, but there is no problem with that. If any of them become zero, return 0
import java.util.Random;
class SDC {
// Driver code
public static void main(String[] args)
{
// Array from 0 to 51
int a[] = {0, 1, 2, 3, 4, 5, 6, 7, 8,
9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29,
30, 31, 32, 33, 34, 35, 36,
37, 38, 39, 40, 41, 42, 43,
44, 45, 46, 47, 48, 49, 50,
51};
shuffle(a, 52);
}
}
Given a password entered by the user, check its strength and suggest some password if it is not strong.
Criteria for strong password is as follows :
A password is strong if it has :
7
1. At least 8 characters
2. At least one special char
3. At least one number
4. At least one upper and one lower case char.
Input : keshav123
Output : Suggested Password
k(eshav12G3
keshav1@A23
keGshav1$23
kesXhav@123
keAshav12$3
kesKhav@123
kes$hav12N3
$kesRhav123
Input: rakesh@1995kumar
Output: Your Password is Strong
Procedure:
Check the input password for its strength if it fulfills all the criteria, then it is strong password else check
for the absent characters in it, and return the randomly generated password to the user.
8
strong, it will suggest*/
static void generate_password(int n, StringBuilder p)
{
// Driver code
public static void main(String[] args)
{
StringBuilder input_String = new StringBuilder("iare@2024");
generate_password(input_String.length(), input_String);
}
}
Reservoir Sampling is a family of randomized algorithms for randomly choosing k samples from a list
of n items, where n is either a very large or unknown number. Typically, n is large enough that the list
doesn’t fit into main memory.
Example: A list of search queries in Google and Facebook.
So we are given a big array (or stream) of numbers (to simplify), and we need to write an efficient
function to randomly select k numbers where 1 <= k <= n.
Let the input array be stream [].
A simple solution is to create an array reservoir [] of maximum size k. One by one randomly select an
item from stream [0..n-1]. If the selected item is not previously selected, then put it in reservoir []. To
check if an item is previously selected or not, we need to search the item in reservoir []. The time
complexity of this algorithm will be O(k^2). This can be costly if k is big. Also, this is not efficient if the
input is in the form of a stream.
It can be solved in O(n) time. The solution also suits well for input in the form of stream.
Steps to get best solution:
1) Create an array reservoir r[0..k-1] and copy first k items of stream[] to it.
2) Now one by one consider all items from (k+1) th item to nth item
a) Generate a random number from 0 to i where i is the index of the current item in stream[]. Let the
generated random number is j.
b) If j is in range 0 to k-1, replace reservoir[j] with stream[i]
9
…
System.out.println(
"Following are k randomly selected items");
System.out.println(Arrays.toString(reservoir));
}
A tree data structure is a hierarchical structure that is used to represent and organize data in a way that is
easy to navigate and search. It is a collection of nodes that are connected by edges and has a hierarchical
relationship between the nodes.
class BT {
10
…
}
// Driver code
public static void main(String[] args)
{
// Number of nodes
int N = 7, Root = 1;
adj.get(1).add(3);
adj.get(3).add(1);
adj.get(1).add(4);
adj.get(4).add(1);
adj.get(2).add(5);
adj.get(5).add(2);
11
adj.get(2).add(6);
adj.get(6).add(2);
adj.get(4).add(7);
adj.get(7).add(4);
12
2. Traverse the left subtree, i.e., call Preorder(left->subtree)
3. Traverse the right subtree, i.e., call Preorder(right->subtree)
class BinaryTree {
// Driver code
public static void main(String[] args)
{
BinaryTree tree = new BinaryTree();
tree.root = new Node(1);
tree.root.left = new Node(2);
13
tree.root.right = new Node(3);
tree.root.left.left = new Node(4);
tree.root.left.right = new Node(5);
// Function call
System.out.println(
"Inorder traversal of binary tree is ");
tree.printInorder(tree.root);
System.out.println(
"Preorder traversal of binary tree is ");
tree.printPreorder(tree.root);
System.out.println(
"Postorder traversal of binary tree is ");
tree.printPostorder(tree.root);
}
}
14
is at top of stack, then remove the right child from stack,
push the root back and set root as root's right child.
b) Else print root's data and set root as NULL.
2.3 Repeat steps 2.1 and 2.2 while stack is not empty.
//Inorder Traversal
class Node
{
int data;
Node left, right;
15
// Preorder traversal
// A binary tree node
class Node {
int data;
Node left, right;
Node(int item)
{
data = item;
left = right = null;
}
}
class BinaryTree {
Node root;
void iterativePreorder() {
iterativePreorder(root);
}
//Postorder Traversal
// A binary tree node
16
class Node {
int data;
Node left, right;
Node(int item)
{
data = item;
left = right;
}
}
class BinaryTree {
Node root;
ArrayList<Integer> list = new ArrayList<Integer>();
// Write code here
………
}
// Driver program to test above functions
public static void main(String args[])
{
BinaryTree tree = new BinaryTree();
System.out.println(
"Post order traversal of binary tree is :");
System.out.println(mylist);
}
}
2.3 Hashing
Hashing is a technique or process of mapping keys, and values into the hash table by using a hash function.
It is done for faster access to elements. The efficiency of mapping depends on the efficiency of the hash
function used.In this case, the find_second_largest method calls the find_largest() function via implicit
17
recursion to locate the second-largest number in a provided list of numbers. Implicit recursion can be used
in this way to get the second-largest integer without having to write any more code
Let a hash function H(x) maps the value x at the index x%10 in an Array. For example if the list of values is
[11,12,13,14,15] it will be stored at positions {1,2,3,4,5} in the array or Hash table respectively.
Given four sorted arrays each of size n of distinct elements. Given a value x. The problem is to count
all quadruples(group of four numbers) from all the four arrays whose sum is equal to x.
Note: The quadruple has an element from each of the four arrays.
Examples:
Input : arr1 = {1, 4, 5, 6},
arr2 = {2, 3, 7, 8},
arr3 = {1, 4, 6, 10},
arr4 = {2, 4, 7, 8}
n = 4, x = 30
Output : 4
The quadruples are:
(4, 8, 10, 8), (5, 7, 10, 8),
(5, 8, 10, 7), (6, 7, 10, 7)
Input : For the same above given fours arrays
x = 25
Output : 14
18
int arr3[] = {1, 4, 6, 10};
int arr4[] = {2, 4, 7, 8};
int n = arr1.length;
int x = 30;
System.out.println("Count = "
+ countQuadruples(arr1, arr2, arr3,
arr4, n, x));
}
}
class Graph {
int vertices;
LinkedList<Integer>[] adjList;
19
public static void main(String[] args)
{
// Number of vertices in the graph
int vertices = 5;
// Create a graph
Graph graph = new Graph(vertices);
# Constructor
def __init__(self):
# Default dictionary to store graph
self.graph = defaultdict(list)
20
Output: Breadth First Traversal starting from vertex 0: 0 1 2 3 4
Depth First Traversal (DFT) for a graph is similar to Depth First Traversal of a tree. The only catch here is,
that, unlike trees, graphs may contain cycles (a node may be visited twice). To avoid processing a node more
than once, use a boolean visited array. A graph can have more than one DFS traversal.
For a given graph G, print DFS traversal from a given source vertex.
Input: n = 4, e = 6
0 -> 1, 0 -> 2, 1 -> 2, 2 -> 0, 2 -> 3, 3 -> 3
Output: DFS from vertex 1: 1 2 0 3
Explanation:
DFS Diagram:
Input: n = 4, e = 6
2 -> 0, 0 -> 2, 1 -> 2, 0 -> 1, 3 -> 3, 1 -> 3
Explanation:
DFS Diagram:
// Constructor
@SuppressWarnings("unchecked") Graph(int v)
{
V = v;
21
adj = new LinkedList[v];
for (int i = 0; i < v; ++i)
adj[i] = new LinkedList();
}
// Driver Code
public static void main(String args[])
{
Graph g = new Graph(4);
g.addEdge(0, 1);
g.addEdge(0, 2);
g.addEdge(1, 2);
g.addEdge(2, 0);
g.addEdge(2, 3);
g.addEdge(3, 3);
System.out.println(
"Following is Depth First Traversal "
+ "(starting from vertex 2)");
// Function call
g.DFS(2);
}
}
22
Heap Sort Procedure:
First convert the array into heap data structure using heapify, then one by one delete the root node of the
Max-heap and replace it with the last node in the heap and then heapify the root of the heap. Repeat this
process until size of heap is greater than 1.
• Build a heap from the given input array.
• Repeat the following steps until the heap contains only one element:
• Swap the root element of the heap (which is the largest element) with the last element of the
heap.
• Remove the last element of the heap (which is now in the correct position).
• Heapify the remaining elements of the heap.
• The sorted array is obtained by reversing the order of the elements in the input array.
// Driver's code
23
public static void main(String args[])
{
int arr[] = { 12, 11, 13, 5, 6, 7 };
int N = arr.length;
// Function call
HeapSort ob = new HeapSort();
ob.sort(arr);
24
3.1 Quick Sort
QuickSort is a sorting algorithm based on the Divide and Conquer algorithm that picks an element as a
pivot and partitions the given array around the picked pivot by placing the pivot in its correct position in
the sorted array. The key process in quickSort is a partition(). The target of partitions is to place the pivot
(any element can be chosen to be a pivot) at its correct position in the sorted array and put all smaller
elements to the left of the pivot, and all greater elements to the right of the pivot. Partition is done
recursively on each side of the pivot after the pivot is placed in its correct position and this finally sorts the
array.
25
{
// If current element is smaller than the pivot
if (arr[j] < pivot)
{
i++; // increment index of smaller element
swap arr[i] and arr[j]
}
}
swap arr[i + 1] and arr[end])
return (i + 1)
}
class QS {
// Driver Code
public static void main(String[] args)
{
int[] arr = { 10, 7, 8, 9, 1, 5 };
int N = arr.length;
26
// Function call
quickSort(arr, 0, N - 1);
System.out.println("Sorted array:");
printArr(arr);
}
}
class MergeSort {
void merge(int arr[], int l, int m, int r)
{
// Write code here
… }
27
// A utility function to print array of size n
static void printArray(int arr[])
{
// Write code here
…
}
// Driver code
public static void main(String args[])
{
int arr[] = { 12, 11, 13, 5, 6, 7 };
Given two binary strings that represent value of two integers, find the product of two strings using
Karatsuba algorithm for fast multiplication. For example, if the first bit string is “1100” and second bit
string is “1010”, output should be 120. For simplicity, let the length of two strings be same and be n.
or this algorithm, two n-digit numbers are taken as the input and the product of the two number is
obtained as the output.
Step 1 − In this algorithm we assume that n is a power of 2.
Step 2 − If n = 1 then we use multiplication tables to find P = XY.
Step 3 − If n > 1, the n-digit numbers are split in half and represent the number using the formulae −
X = 10n/2X1 + X2
Y = 10n/2Y1 + Y2
28
P = 10n (X1Y1) + 10n/2 (X1Y2 + X2Y1) + X2Y2.
Step 6 − Recursively call the algorithm by passing the sub problems (X1, Y1), (X2, Y2) and (X1 + X2, Y1 + Y2)
separately. Store the returned values in variables U, V and W respectively.
public class Main {
static long karatsuba(long X, long Y) {
// Base Case
if (X < 10 && Y < 10)
return X * Y;
// Write Code Here
……
}
static int get_size(long value) {
// Write Code Here
……
}
public static void main(String args[]) {
// two numbers
long x = 145623;
long y = 653324;
System.out.print("The final product is: ");
long product = karatsuba(x, y);
System.out.println(product);
}
}
Strassen’s Matrix multiplication can be performed only on square matrices where n is a power of 2. Order
of both of the matrices are n × n.
Divide X, Y and Z into four (n/2)×(n/2) matrices as represented below −
29
/** Java Program to Implement Strassen Algorithm**/
import java.util.Scanner;
/** Class Strassen **/
public class Strassen
{ /** Function to multiply matrices **/
public int[][] multiply(int[][] A, int[][] B)
{
int n = A.length;
int[][] R = new int[n][n];
/** base case **/
if (n == 1)
R[0][0] = A[0][0] * B[0][0];
else
{ ………….Write Code Here………………
}
}
/** Function to sub two matrices **/
public int[][] sub(int[][] A, int[][] B)
{
……….Write Code Here………..
return C;
}
/** Function to add two matrices **/
public int[][] add(int[][] A, int[][] B)
{
……Write Code Here………….
return C;
}
/** Function to split parent matrix into child matrices **/
public void split(int[][] P, int[][] C, int iB, int jB) { ….Write
Code….}
/** Function to join child matrices intp parent matrix **/
30
public void join(int[][] C, int[][] P, int iB, int jB) { ….Write
Code….}
/** Main function **/
public static void main (String[] args)
{
….Write Code Here…..
}
}
We are given an array of n points in the plane, and the problem is to find out the closest pair of points in
the array. This problem arises in a number of applications. For example, in air-traffic control, you may want
to monitor planes that come too close together, since this may indicate a possible collision. Recall the
following formula for distance between two points p and q.
The Brute force solution is O(n^2), compute the distance between each pair and return the smallest. We
can calculate the smallest distance in O(nLogn) time using Divide and Conquer strategy. In this post, a O(n
x (Logn)^2) approach is discussed. We will be discussing a O(nLogn) approach in a separate post.
Algorithm
Following are the detailed steps of a O (n (Logn)^2) algorithm.
Input: An array of n points P []
Output: The smallest distance between two points in the given array.
As a pre-processing step, the input array is sorted according to x coordinates.
1) Find the middle point in the sorted array, we can take P[n/2] as middle point.
2) Divide the given array in two halves. The first subarray contains points from P[0] to P[n/2]. The second
subarray contains points from P[n/2+1] to P[n-1].
3) Recursively find the smallest distances in both subarrays. Let the distances be dl and dr. Find the
minimum of dl and dr. Let the minimum be d.
4) From the above 3 steps, we have an upper bound d of minimum distance. Now we need to consider the
pairs such that one point in pair is from the left half and the other is from the right half. Consider the vertical
line passing through P[n/2] and find all points whose x coordinate is closer than d to the middle vertical
line. Build an array strip [] of all such points.
31
5) Sort the array strip[] according to y coordinates. This step is O(nLogn). It can be optimized to O(n) by
recursively sorting and merging.
6) Find the smallest distance in strip[]. This is tricky. From the first look, it seems to be a O(n^2) step, but it
is actually O(n). It can be proved geometrically that for every point in the strip, we only need to check at
most 7 points after it (note that strip is sorted according to Y coordinate).
7) Finally return the minimum of d and distance calculated in the above step (step 6)
import java.text.DecimalFormat;
import java.util.Arrays;
import java.util.Comparator;
// A divide and conquer program in Java to find the smallest distance from
// a given set of points A structure to represent a Point in 2D plane
class Point {
public int x;
public int y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
32
public class ClosestPoint {
// Driver code
public static void main(String[] args) { ………….. Write Code Here……..
DecimalFormat df = new DecimalFormat("#.######");
System.out.println("The smallest distance is " +
df.format(Point.closest(P, P.length)));
}
Given a n by n board where n is of form 2k where k >= 1 (Basically n is a power of 2 with minimum value
as 2). The board has one missing cell (of size 1 x 1). Fill the board using L shaped tiles. A L shaped tile is a
2 x 2 square with one cell of size 1×1 missing.
This problem can be solved using Divide and Conquer. Below is the recursive algorithm.
// n is size of given square, p is location of missing cell
Tile(int n, Point p)
1) Base case: n = 2, A 2 x 2 square with one cell missing is nothing but a tile and can be filled with a single
tile.
2) Place a L shaped tile at the center such that it does not cover the n/2 * n/2 subsquare that has a missing
square. Now all four subsquares of size n/2 x n/2 have a missing cell (a cell that doesn't
need to be filled). See figure 2 below.
3) Solve the problem recursively for following four. Let p1, p2, p3 and
p4 be positions of the 4 missing cells in 4 squares.
a) Tile(n/2, p1)
33
b) Tile(n/2, p2)
c) Tile(n/2, p3)
d) Tile(n/2, p3)
public class TP
{
static int size_of_grid, b, a, cnt = 0;
34
static int[][] arr = new int[128][128];
// Driver code
public static void main(String[] args)
{
// size of box
size_of_grid = 8;
// Coordinates which will be marked
a = 0; b = 0;
// Here tile can not be placed
arr[a][b] = -1;
tile(size_of_grid, 0, 0);
// The grid is
for (int i = 0; i < size_of_grid; i++)
{
for (int j = 0; j < size_of_grid; j++)
System.out.print(arr[i][j] + " ");
System.out.println();;
}
}
}
Given n rectangular buildings in a 2-dimensional city, computes the skyline of these buildings, eliminating
hidden lines. The main task is to view buildings from a side and remove all sections that are not visible. All
buildings share a common bottom and every building is represented by a triplet (left, ht, right)
35
A skyline is a collection of rectangular strips. A rectangular strip is represented as a pair (left, ht) where left
is x coordinate of the left side of the strip and ht is the height of the strip.
Input: buildings[][] =
{ {1, 11, 5}, {2, 6, 7}, {3, 13, 9}, {12, 7, 16}, {14, 3, 25}, {19, 18, 22}, {23, 13, 29}, {24, 4, 28} }
Output: { {1, 11}, {3, 13}, {9, 0}, {12, 7}, {16, 3}, {19, 18}, {22, 3}, {23, 13}, {29, 0} }
Explanation:
The skyline is formed based on the key-points (representing by “green” dots) eliminating hidden walls of
the buildings.
The Skyline Problem:
Input: buildings[ ][ ] = { {1, 11, 5} }
Output: { {1, 11}, {5, 0}
We can find Skyline using Divide and Conquer. The idea is similar to Merge Sort, divide the given set of
buildings in two subsets. Recursively construct skyline for two halves and finally merge the two skylines.
Start from first strips of two skylines, compare x coordinates. Pick the strip with smaller x coordinate and
add it to result. The height of added strip is considered as maximum of current heights from skyline1 and
skyline2.
36
this.ht = ht;
}
}
// Skyline: To represent Output(An array of strips)
class SkyLine {
List<Strip> arr;
int capacity, n;
37
new Building(23, 13, 29), new Building(24, 4, 28)};
Given that there are N books and M students. Also given are the number of pages in each book in
ascending order. The task is to assign books in such a way that the maximum number of pages assigned
to a student is minimum, with the condition that every student is assigned to read some consecutive
books. Print that minimum number of pages.
Example :
Input: N = 4, pages[] = {12, 34, 67, 90}, M = 2
Output: 113
Explanation: There are 2 number of students. Books can be distributed in following combinations:
1. [12] and [34, 67, 90] -> Max number of pages is allocated to student ‘2’ with 34 + 67 + 90 = 191
pages
2. [12, 34] and [67, 90] -> Max number of pages is allocated to student ‘2’ with 67 + 90 = 157 pages
3. [12, 34, 67] and [90] -> Max number of pages is allocated to student ‘1’ with 12 + 34 + 67 = 113
pages
Of the 3 cases, Option 3 has the minimum pages = 113.
Approach to solve this problem is to use Divide and Conquer, based on Binary Search idea:
Case 1: When no valid answer exists.
• If the number of students is greater than the number of books (i.e, M > N), In this case at least 1
student will be left to which no book has been assigned.
Case 2: When a valid answer exists.
• The maximum possible answer could be when there is only one student. So, all the book will be
assigned to him and the result would be the sum of pages of all the books.
• The minimum possible answer could be when number of student is equal to the number of book
(i.e, M == N) , In this case all the students will get at most one book. So, the result would be the
maximum number of pages among them (i.e, maximum(pages[])).
• Hence, we can apply binary search in this given range and each time we can consider the mid value
as the maximum limit of pages one can get. And check for the limit if answer is valid then update
the limit accordingly.
Below is the approach to solve this problem using Divide and Conquer:
• Calculate the mid and check if mid number of pages can be assigned to students such that all
students will get at least one book.
• If yes, then update the result and check for the previous search space (end = mid-1)
• Otherwise, check for the next search space (start = mid+1)
38
public class NM {
// Utility method to check if current minimum value is feasible or not.
static boolean isPossible(int arr[], int n, int m, int curr_min)
{
int studentsRequired = 1;
int curr_sum = 0;
// Write code here
……
Given k sorted linked lists, merge them into a single list in increasing order.
We already know that Two Linked Lists can be Merged in O(n) time and O(1) space (For arrays, O(n) space
is required). The idea is to pair up k lists and merge each pair in linear time using the O(1) space. After the
first cycle, K/2 lists are left each of size 2×N. After the second cycle, K/4 lists are left each of size 4×N and
so on. Repeat the procedure until we have only one list left.
39
Given an n x n matrix, where every row and column is sorted in increasing order. Given a key, how to
decide whether this key is in the matrix. This problem will be a very good example for divide and conquer
algorithm.
1) Find the middle element.
2) If middle element is same as key return.
3) If middle element is lesser than key then
….3a) search submatrix on lower side of middle element
….3b) Search submatrix on right hand side.of middle element
4) If middle element is greater than key then
….4a) search vertical submatrix on left side of middle element
….4b) search submatrix on right hand side.Shell Sort Procedure:
class SearchInMatrix
{
public static void main(String[] args)
{
int[][] mat = new int[][] { {10, 20, 30, 40},
{15, 25, 35, 45},
{27, 29, 37, 48},
{32, 33, 39, 50}};
int rowcount = 4,colCount=4,key=50;
for (int i=0; i<rowcount; i++)
for (int j=0; j<colCount; j++)
search(mat, 0, rowcount-1, 0, colCount-1, mat[i][j]);
}
40
// Write code here
……
}
}
5. Greedy Technique
Greedy Algorithm is optimization method. When the problem has many feasible solutions with
different cost or benefit, finding the best solution is known as an optimization problem and the
best solution is known as the optimal solution.
The greedy algorithm derives the solution step by step, by looking at the information available
at the current moment. It does not look at future prospects. Decisions are completely locally
optimal. This method constructs the solution simply by looking at current benefit without
exploring future possibilities and hence they are known as greedy. The choice made under
greedy solution procedure are irrevocable, means once we have selected the local best
solution, it cannot be backtracked. Thus, a choice made a t each step in the greedy method
should be:
▪ Feasible: choice should satisfy problem constraints.
▪ Locally optimal: Best solution from all feasible solution at the current stage should be
selected.
▪ Irrevocable: Once the choice is made, it cannot be altered, i.e. if a feasible solution is
selected (rejected) in step i, it cannot be rejected (selected) in subsequent stages.
5.1 Optimal Storage on Tapes
Optimal Storage on Tapes is one of the applications in the Greedy Method. The objective of this algorithm
is to find the Optimal retrieval time for accessing programs that are stored on tape.
This algorithm works in steps. In each step, it selects the best available options until all options are finished.
EXPLANATION
• There are 'n' programs that are to be stored on a computer tape of length (L).
• Associated with each program (i) is a length (l).
• Let the programs are stored in the order (I = i1, i2, i3, ....)
41
• If all programs are retrieved equally often then the expected or Mean Retrieval Time (MRT) is,
// Java Program to find the order of programs for which MRT is minimized
import java.io.*;
import java .util.*;
class GFG
{
// This functions outputs the required order and Minimum Retrieval Time
static void findOrderMRT(int []L, int n)
{ // Here length of i'th program is L[i]
Arrays.sort(L);
System.out.print("Optimal order in which " +
"programs are to be stored is: ");
// Write code Here
…………………
// MRT - Minimum Retrieval Time
double MRT = 0;
for (int i = 0; i < n; i++)
{
// Write code Here
…………………
}
System.out.print( "Minimum Retrieval Time" +
" of this order is " + MRT);
}
// Driver Code
public static void main (String[] args)
{
int []L = { 2, 5, 4 };
int n = L.length;
findOrderMRT(L, n);
}
}
42
Set of jobs with deadlines and profits are taken as an input with the job scheduling algorithm and scheduled
subset of jobs with maximum profit are obtained as the final output.
Step1: Find the maximum deadline value from the input set of jobs.
Step2: Once, the deadline is decided, arrange the jobs in descending order of their profits.
Step3: Selects the jobs with highest profits, their time periods not exceeding the maximum deadline.
Step4: The selected set of jobs are the output.
// Driver's code
public static void main(String args[])
{
ArrayList<Job> arr = new ArrayList<Job>();
arr.add(new Job('a', 2, 100));
arr.add(new Job('b', 1, 19));
arr.add(new Job('c', 2, 27));
arr.add(new Job('d', 1, 25));
arr.add(new Job('e', 3, 15));
43
5.3 Single source shortest path - Dijkstra’s Algorithm
Dijkstra’s Algorithm is also known as Single Source Shortest Path (SSSP) problem. It is used to find the
shortest path from source node to destination node in graph.
The graph is widely accepted data structure to represent distance map. The distance between cities
effectively represented using graph.
▪ Dijkstra proposed an efficient way to find the single source shortest path from the weighted graph.
For a given source vertex s, the algorithm finds the shortest path to every other vertex v in the graph.
1. Initializes the distance of source vertex to zero and remaining all other vertices to infinity.
2. Set source node to current node and put remaining all nodes in the list of unvisited vertex list.
Compute the tentative distance of all immediate neighbour vertex of the current node.
3. If the newly computed value is smaller than the old value, then update it.
4. Weight updating in Dijkstra’s Algorithm: When all the neighbours of a current node are explored,
mark it as visited. Remove it from unvisited vertex list. Mark the vertex from unvisited vertex list
with minimum distance and repeat the procedure.
5. Stop when the destination node is tested or when unvisited vertex list becomes empty.
44
// Driver's code
public static void main(String[] args)
{ // Write Code Here
……….. …………
// Function call
t.dijkstra(graph, 0);
}
}
Prim’s Algorithm
Prim’s Algorithm begins with a single Node and adds up adjacent nodes one by one by discovering all of
the connected edges along the way. Edges with the lowest weights that don't generate cycles are chosen
for inclusion in the MST structure. As a result, we can claim that Prim's algorithm finds the globally best
answer by making locally optimal decisions.
Steps involved in Prim’s algorithms are mentioned below:
Step 1: Choose any vertex as a starting vertex.
Step 2: Pick an edge connecting any tree vertex and fringe vertex (adjacent vertex to visited vertex) having
the minimum edge weight.
Step 3: Add the selected edge to MST only if it doesn't form any closed cycle.
Step 4: Keep repeating steps 2 and 3 until the fringe vertices exist.
Step 5: End.
45
….. ….. …. }
}
public static void main(String[] args)
{ MST t = new MST();
int graph[][] = new int[][] { { 0, 2, 0, 6, 0 },
// Write Code Here
….. ….. ….
t.primMST(graph);
}
}
Kruskal’s Algorithm
Kruskal's approach sorts all the edges in ascending order of edge weights and only adds nodes to the tree
if the chosen edge does not form a cycle. It also selects the edge with the lowest cost first and the edge
with the highest cost last. As a result, we can say that the Kruskal’s Algorithm makes a locally optimum
decision in the hopes of finding the global optimal solution. Hence, this algorithm can also be considered
as a Greedy Approach.
The steps involved in Kruskal’s algorithm to generate a minimum spanning tree are:
Step 1: Sort all edges in increasing order of their edge weights.
Step 2: Pick the smallest edge.
Step 3: Check if the new edge creates a cycle or loop in a spanning tree.
Step 4: If it doesn’t form the cycle, then include that edge in MST. Otherwise, discard it.
Step 5: Repeat from step 2 until it includes |V| - 1 edges in MST.
46
{ // Write Code Here
…. … ….
}
system.out.println( "Following are the edges of the constructed MST:");
int minCost = 0;
// Write Code Here
…. … ….
}
// Function to unite two disjoint sets
private static void union(Subset[] subsets, int x, int y)
{ // Write Code Here
…. … ….
}
// Function to find parent of a set
private static int findRoot(Subset[] subsets, int i)
{
if (subsets[i].parent == i)
return subsets[i].parent;
subsets[i].parent
= findRoot(subsets, subsets[i].parent);
return subsets[i].parent;
}
}
Algorithm:
The method which is used to construct optimal prefix code is called Huffman coding.
This algorithm builds a tree in bottom up manner. We can denote this tree by T
47
Let, |c| be number of leaves |c| -1 are number of operations required to merge the nodes. Q be the priority
queue which can be used while constructing binary heap.
3. Create a new internal node with a frequency equal to the sum of the two nodes frequencies.
Make the first extracted node as its left child and the other extracted node as its right child. Add
this node to the min heap.
4. Repeat steps#2 and #3 until the heap contains only one node. The remaining node is the root
node and the tree is complete.
Let us understand the algorithm with an example:
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Scanner;
class Huffman {
// recursive function to print the huffman-code through the tree raversal.
// Here s is the huffman - code generated.
public static void printCode(HuffmanNode root, String s)
{ // Write Code Here
… … …
}
// main function
public static void main(String[] args)
{ Scanner s = new Scanner(System.in);
int n = 6;
char[] charArray = { 'a', 'b', 'c', 'd', 'e', 'f' };
48
int[] charfreq = { 5, 9, 12, 13, 16, 45 };
PriorityQueue<HuffmanNode>
Q = new PriorityQueue<HuffmanNode>(n, new MyComparator());
for (int i = 0; i < n; i++) {
// Write Code Here
… …. …
}
// create a root node
HuffmanNode root = null;
6. Greedy Technique
6.1 Assign Mice to Holes
Problem Statement and Example
Given the positions of mice and holes along a line, and the speed of each mouse, the task is to find the
arrangement of mice in the holes that minimizes the maximum time taken for any mouse to reach its hole.
Each mouse should be assigned to a unique hole, and the order of mice and holes should be preserved.
The goal is to arrange the mice in the holes in a way that minimizes the maximum time taken for any
mouse to reach its hole.
49
2. Iterate through the sorted arrays and calculate the absolute difference between each mouse's
position and its corresponding hole's position.
3. Track the maximum absolute difference during the iteration.
4. The maximum absolute difference represents the time it takes for the mouse to reach its hole in
the optimal arrangement.
Algorithm Explanation
// Java program to find the minimum time to place all mice in all holes.
import java.util.*;
public class GFG
{
// Returns minimum time required to place mice in holes.
public int assignHole(ArrayList<Integer> mice,ArrayList <Integer> holes)
{
if (mice.size() != holes.size())
return -1;
/* Sort the lists */
// Write Code Here
… …. …
/* finding max difference between ith mice and hole */
}
50
6.2 Minimum Cost to cut a board into squares
A board of length m and width n is given, we need to break this board into m*n squares such that cost of
breaking is minimum. cutting cost for each edge will be given for the board. In short, we need to choose
such a sequence of cutting such that cost is minimized.
Examples:
51
// Java program to divide a board into m*n squares
import java.util.Arrays;
import java.util.Collections;
class GFG
{
// method returns minimum cost to break board into m*n squares
static int minimumCostOfBreaking(Integer X[], Integer Y[], int m, int n)
{ int res = 0;
// sort the horizontal cost in reverse order
//Write Code here
….. ….. …..
while (i < m && j < n)
{//Write Code here
….. ….. …..
// Driver program
public static void main(String arg[])
{
int m = 6, n = 4;
Integer X[] = {2, 1, 3, 1, 4};
Integer Y[] = {4, 1, 2};
System.out.print(minimumCostOfBreaking(X, Y, m-1, n-1));
}
}
Given are N ropes of different lengths, the task is to connect these ropes into one rope
with minimum cost, such that the cost to connect two ropes is equal to the sum of their lengths.
Examples:
Input: arr[] = {4,3,2,6} , N = 4
Output: 29
Explanation:
1. First, connect ropes of lengths 2 and 3. Now we have three ropes of lengths 4, 6, and 5.
2. Now connect ropes of lengths 4 and 5. Now we have two ropes of lengths 6 and 9.
3. Finally connect the two ropes and all ropes have connected.
52
Input: arr[] = {1, 2, 3} , N = 3
Output: 9
Explanation:
1. First, connect ropes of lengths 1 and 2. Now we have two ropes of lengths 3 and 3.
2. Finally connect the two ropes and all ropes have connected.
Approach: If we observe the above problem closely, we can notice that the lengths of the ropes which are
picked first are included more than once in the total cost. Therefore, the idea is to connect the smallest
two ropes first and recur for the remaining ropes. This approach is similar to Huffman Coding. We put the
smallest ropes down the tree so they can be repeated multiple times rather than the longer ones.
53
+ " ropes is "
+ minCost(len, size));
}
}
6.4 Rearrange a string so that all same characters become d distance away
Given a string and a positive integer d. Some characters may be repeated in the given string. Rearrange
characters of the given string such that the same characters become d distance away from each other.
Note that there can be many possible rearrangements, the output should be one of the possible
rearrangements. If no such arrangement is possible, that should also be reported.
The expected time complexity is O(n + m log(MAX)) Here n is the length of string, m is the count of
distinct characters in a string and MAX is the maximum possible different characters.
Examples:
Input: "abb", d = 2
Output: "bab"
Input: "aacbbc", d = 3
Output: "abcabc"
Input: "aaa", d = 2
Output: Cannot be rearranged
The approach to solving this problem is to count frequencies of all characters and consider the most
frequent character first and place all occurrences of it as close as possible. After the most frequent
character is placed, repeat the same process for the remaining characters.
1. Let the given string be str and size of string be n
2. Traverse str, store all characters and their frequencies in a Max Heap MH(implemented using
priority queue). The value of frequency decides the order in MH, i.e., the most frequent character
is at the root of MH.
3. Make all characters of str as ‘\0’.
4. Do the following while MH is not empty.
• Extract the Most frequent character. Let the extracted character be x and its frequency be f.
• Find the first available position in str, i.e., find the first ‘\0’ in str.
• Let the first position be p. Fill x at p, p+d,.. p+(f-1)d
54
// The function returns next eligible character with maximum frequency
// (Greedy!!) and zero or negative distance
static int nextChar(int freq[], int dist[])
{
// Write code Here
…. ….. …
}
// The main function that rearranges input string 'str'
static int rearrange(char str[], char out[], int d)
{
int n = str.length;
return 1;
}
// Driver code
public static void main(String[] args)
{
char str[] = "aaaabbbcc".toCharArray();
int n = str.length;
// To store output
char []out = new char[n];
Problem Statement
Suppose you are given that there are few friends. They have borrowed money from each other due to
which there will be some cash flow on the network. Our main aim is to design an algorithm by which the
total cash flow among all the friends is minimized.
For example:
There are three friends A1, A2, A3; you have to show the settlement of input debts between them.
55
Solution using Greedy Approach
The greedy approach is used to build the solution in pieces, and this is what we want to minimize the
cash flow. At every step, we will settle all the amounts of one person and recur for the remaining n-1
persons.
Calculate the net amount for every person, which can be calculated by subtracting all the debts, i.e.,
the amount to be paid from all credit, i.e., the amount to be paid to him. After this, we will find two
persons with the maximum and the minimum net amounts. The person with a minimum of two is our
first person to be settled and removed from the list.
Following algorithm will be done for every person varying 'i' from 0 to n-1.
1. The first step will be to calculate the net amount for every person and store it in an amount array.
Net amount = sum(received money) - sum(sent money).
2. Find the two people that have the most credit and the most debt. Let the maximum amount to be
credited from maximum creditor be max_credit and the maximum amount to be debited from
maximum debtor be max_debit. Let the maximum debtor be debt and maximum creditor be cred.
3. Let the minimum of two amounts be 'y'.
4. If y equals max_credit, delete cred from the list and repeat for the remaining (n-1) people.
5. If y equals max_debit, delete debt from the group of people and repeat for recursion.
6. If the amount is 0, then the settlement is done.
class GFG
{
// Number of persons (or vertices in the graph)
static final int N = 3;
56
// A utility function that returns index of maximum value in arr[]
static int getMax(int arr[])
{
// Write Code Here
….. …… ….
}
// A utility function to return minimum of 2 values
static int minOf2(int x, int y)
{
return (x < y) ? x: y;
}
Given n cities and distances between every pair of cities, select k cities to place warehouses (or ATMs or
Cloud Server) such that the maximum distance of a city to a warehouse (or ATM or Cloud Server) is
minimized.
For example consider the following four cities, 0, 1, 2, and 3, and the distances between them, how to
place 2 ATMs among these 4 cities so that the maximum distance of a city to an ATM is minimized.
57
There is no polynomial-time solution available for this problem as the problem is a known NP-Hard
problem. There is a polynomial-time Greedy approximate algorithm, the greedy algorithm provides a
solution that is never worse than twice the optimal solution. The greedy solution works only if the
distances between cities follow Triangular Inequality (The distance between two points is always smaller
than the sum of distances through a third point).
Approximate Greedy Algorithm:
1. Choose the first centre arbitrarily.
2. Choose remaining k-1 centres using the following criteria.
• Let c1, c2, c3, … ci be the already chosen centres. Choose
• (i+1)’th centre by picking the city which is farthest from already
• selected centres, i.e, the point p which has following value as maximum
• Min[dist(p, c1), dist(p, c2), dist(p, c3), …. dist(p, ci)]
System.out.println(dist[max]);
// Driver Code
public static void main(String[] args)
{
int n = 4;
58
int[][] weights = new int[][]{ { 0, 4, 8, 5 }, { 4, 0, 10, 7 },
{ 8, 10, 0, 9 }, { 5, 7, 9, 0 } };
int k = 2;
// Function Call
selectKcities(n, weights, k);
}
}
7. Dynamic Programming
Dynamic Programming (DP) is defined as a technique that solves some particular type of
problems in Polynomial Time. Dynamic Programming solutions are faster than the exponential
brute method and can be easily proved their correctness. Dynamic Programming is mainly an
optimization over plain recursion. Wherever we see a recursive solution that has repeated calls
for same inputs, we can optimize it using Dynamic Programming. The idea is to simply store the
results of subproblems, so that we do not have to re-compute them when needed later. This
simple optimization reduces time complexities from exponential to polynomial.
Irrevocable: Once the choice is made, it cannot be altered, i.e. if a feasible solution is selected
(rejected) in step i, it cannot be rejected (selected) in subsequent stages.
At first the output matrix is same as given cost matrix of the graph. After that the output matrix will be
updated with all vertices k as the intermediate vertex.
The time complexity of this algorithm is O(V3), here V is the number of vertices in the graph.
Input − The cost matrix of the graph.
036∞∞∞∞
3021∞∞∞
620142∞
∞1102∞4
∞∞42021
∞∞2∞201
∞∞∞4110
Output − Matrix of all pair shortest path.
59
0345677
3021344
4201323
5110233
6332021
7423201
7433110
Algorithm
floydWarshal(cost)
Input − The cost matrix of given Graph.
Output − Matrix to for shortest path between any vertex to any vertex.
Begin
for k := 0 to n, do
for i := 0 to n, do
for j := 0 to n, do
if cost[i,k] + cost[k,j] < cost[i,j], then
cost[i,j] := cost[i,k] + cost[k,j]
done
done
done
display the current cost matrix
End
// Java program for Floyd Warshall All Pairs Shortest Path algorithm.
import java.io.*;
import java.lang.*;
import java.util.*;
class AllPairShortestPath {
final static int INF = 99999, V = 4;
void floydWarshall(int dist[][])
{
// Write Code Here
….. …… …..
printSolution(dist);
}
60
+ "distances between every pair of vertices");
for (int i = 0; i < V; ++i) {
for (int j = 0; j < V; ++j) {
if (dist[i][j] == INF)
System.out.print("INF ");
else
System.out.print(dist[i][j] + " ");
}
System.out.println();
}
}
// Driver's code
public static void main(String[] args)
{
// Provide Input
…. ….. ….
AllPairShortestPath a = new AllPairShortestPath();
a.floydWarshall(graph);
}
}
In an OBST, each node is assigned a weight that represents the probability of the key being searched for.
The sum of all the weights in the tree is 1.0. The expected search cost of a node is the sum of the product
of its depth and weight, and the expected search cost of its children.
To construct an OBST, we start with a sorted list of keys and their probabilities. We then build a table that
contains the expected search cost for all possible sub-trees of the original list. We can use dynamic
programming to fill in this table efficiently. Finally, we use this table to construct the OBST.
The time complexity of constructing an OBST is O(n^3), where n is the number of keys. However, with some
optimizations, we can reduce the time complexity to O(n^2). Once the OBST is constructed, the time
complexity of searching for a key is O(log n), the same as for a regular binary search tree.
The OBST is a useful data structure in applications where the keys have different probabilities of being
searched for. It can be used to improve the efficiency of searching and retrieval operations in databases,
compilers, and other computer programs.
Given a sorted array key [0.. n-1] of search keys and an array freq[0.. n-1] of frequency counts,
where freq[i] is the number of searches for keys[i]. Construct a binary search tree of all keys such that the
total cost of all the searches is as small as possible.
Let us first define the cost of a BST. The cost of a BST node is the level of that node multiplied by its
frequency. The level of the root is 1.
61
Examples:
Input: keys[] = {10, 12}, freq[] = {34, 50}
There can be following two possible BSTs
10 12
\ /
12 10
I II
Frequency of searches of 10 and 12 are 34 and 50 respectively.
The cost of tree I is 34*1 + 50*2 = 134
The cost of tree II is 50*1 + 34*2 = 118
Input: keys[] = {10, 12, 20}, freq[] = {34, 8, 50}
There can be following possible BSTs
10 12 20 10 20
\ / \ / \ /
12 10 20 12 20 10
\ / / \
20 10 12 12
I II III IV V
Among all possible BSTs, cost of the fifth BST is minimum.
Cost of the fifth BST is 1*50 + 2*34 + 3*8 = 142
We can use the recursive solution with a dynamic programming approach to have a more optimized code,
reducing the complexity from O(n^3) from the pure dynamic programming to O(n). To do that, we have
to store the subproblems calculations in a matrix of NxN and use that in the recursions, avoiding
calculating all over again for every recursive call.
// Dynamic Programming Java code for Optimal Binary Search Tree Problem
public class Optimal_BST {
62
….. …. … }
public static void main(String[] args) {
Note: The constraint here is we can either put an item completely into the bag or cannot put it at all [It is
not possible to put a part of an item into the bag].
Note: It should be noted that the above function using recursion computes the same subproblems again
and again. See the following recursion tree, K(1, 1) is being evaluated twice.
In the following recursion tree, K() refers to knapSack(). The two parameters indicated in the following
recursion tree are n and W.
The recursion tree is for following sample inputs.
weight[] = {1, 1, 1}, W = 2, profit[] = {10, 20, 30}
K(3, 2)
/ \
/ \
K(2, 2) K(2, 1)
/ \ / \
/ \ / \
K(1, 2) K(1, 1) K(1, 1) K(1, 0)
/ \ / \ / \
/ \ / \ / \
K(0, 2) K(0, 1) K(0, 1) K(0, 0) K(0, 1) K(0, 0)
Recursion tree for Knapsack capacity 2 units and 3 items of 1 unit weight.
As there are repetitions of the same subproblem again and again we can implement the following idea to
solve the problem.
63
If we get a subproblem the first time, we can solve this problem by creating a 2-D array that can store a
particular state (n, w). Now if we come across the same state (n, w) again instead of calculating it in
exponential complexity we can directly return its result stored in the table in constant time.
// Dynamic Programming Java code for Optimal Binary Search Tree Problem
public class Optimal_BST {
static int optimalSearchTree(int keys[], int freq[], int n) {
int cost[][] = new int[n + 1][n + 1];
// Write Code Here
…. ….. ….
}
static int sum(int freq[], int i, int j) {
int s = 0;
for (int k = i; k <= j; k++) {
if (k >= freq.length)
continue;
s += freq[k];
}
return s;
}
64
that we can take more than one copy of each device so that if one device fails we can use the copy of that
device, which means we can connect the devices parallel.
When the same type of 3 devices is connected parallelly in stage 1 having a reliability 0.9 each then:
public class SeriesSystemReliability {
public static void main(String[] args) {
double[] componentReliabilities = {0.99, 0.98, 0.97, 0.96, 0.95};
double systemReliability =
calculateSeriesSystemReliability(componentReliabilities);
System.out.println("The reliability of the series system is: " +
systemReliability);
}
public static double calculateSeriesSystemReliability(double[]
reliabilities) {
double systemReliability = 1.0; // Start with a system that's
initially 100% reliable
for (double reliability : reliabilities) {
systemReliability *= reliability;
}
return systemReliability;
}
}
▪ In flow shop, m different machines should process n jobs. Each job contains exactly n operations.
The ith operation of the job must be executed on the i th machine. Operations within one job must
be performed in the specified order.
▪ The first operation gets executed on the first machine, then the second operation on the second
machine, and so on. Jobs can be executed in any order. The problem is to determine the optimal
such arrangement, i.e. the one with the shortest possible total job execution makespan.
▪ With two machines, problem can be solved in O(nlogn) time using Johnson’s algorithm. For more
than 2 machines, the problem is NP hard. The goal is to minimize the sum of completion time of
all jobs.
▪ The flow shop contains n jobs simultaneously available at time zero and to be processed by two
machines arranged in series with unlimited storage in between them. The processing time of all
jobs are known with certainty.
▪ It is required to schedule n jobs on machines so as to minimize makespan. The Johnson’s rule for
scheduling jobs in two machine flow shop is given below: In an optimal schedule, job i precedes
job j if min{pi1,pj2} < min{pj1,pi2}. Whereas, pi1 is the processing time of job i on machine 1 and
pi2 is the processing time of job i on machine 2. Similarly, p j1 and pj2 are processing times of job j
on machine 1 and machine 2 respectively.
▪ We can find the optimal scheduling using Dynamic Programming.
65
Algorithm for Flow Shop Scheduling
Johnson’s algorithm for flow shop scheduling is described below:
Algorithm JOHNSON_FLOWSHOP(T, Q)
// T is array of time of jobs, each column indicating time on machine Mi
// Q is queue of jobs
Q=Φ
for j = 1 to n do
t = minimum machine time scanning in booth columns
if t occurs in column 1 then
Add Job j to the first empty slot of Q
else
Add Job j to last empty slot of Q
end
Remove processed job from consideration
end
return Q
66
8. Dynamic Programming
8.1 Sherlock and Cost
Problem Statement and Example
In this challenge, you will be given an array B and must determine an array A. There is a special rule: For all
i, A[i]<=B[i]. That is, A[i] can be any number you choose such that 1<=A[i]<=B[i]. Your task is to select a
series of A[i] given B[i] such that the sum of the absolute difference of consecutive pairs of A is maximized.
This will be the array's cost and will be represented by the variable S below.
For example, if the array B=[1,2,3], we know that 1<=A[1]<=1, 1<=A[2]<=2, and 1<=A[3]<=3. Arrays
meeting those guidelines are:
[1,1,1], [1,1,2], [1,1,3]
[1,2,1], [1,2,2], [1,2,3]
Function Description:
Complete the cost function in the editor below. It should return the maximum value that can be obtained.
cost has the following parameter(s):
B: an array of integers
Input Format
The first line contains the integer t, the number of test cases.
Each of the next t pairs of lines is a test case where:
- The first line contains an integer n, the length of B
- The next line contains n space-separated integers B[i]
Constraints
1<=t<=20
1<n<=105
1<=B[i]<=100
Output Format
For each test case, print the maximum sum on a separate line.
Sample Input
1
5
10 1 10 1 10
Sample Output
36
67
Explanation
The maximum sum occurs when A[1]=A[3]=A[5]=10 and A[2]=A[4]=1. That is 36.
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int b[100000];
int dp[100000][2];
int main()
{
int t;
cin >> t;
while (t--)
{
memset(dp, 0, sizeof(dp));
int n;
cin >> n;
for (int i = 0; i < n; i++)
cin >> b[i];
for (int i = 1; i < n; i++)
{
dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + abs(b[i - 1] - 1));
dp[i][1] = max(dp[i - 1][0] + abs(b[i] - 1), dp[i - 1][1]);
}
cout << max(dp[n - 1][0], dp[n - 1][1]) << endl;
}
return 0;
}
Consider an array, A, of length n. We can split A into contiguous segments called pieces and store them as
another array, B. For example, if A=[1,2,3], we have the following arrays of pieces:
68
Given A, find the total values for all possible B's, sum them together, and print this sum modulo (10 9 + 7)
on a new line.
Input Format
The first line contains a single integer, n, denoting the size of array A.
The second line contains n space-separated integers describing the respective values in A.
Output Format
Print a single integer denoting the sum of the total values for all piece arrays (B's) of A, modulo (10 9 + 7).
Sample Input 1
3
136
Sample Output 1
73
Sample Input 2
5
4 2 9 10 1
Sample Output 2
971
return totalSum;
}
}
Each day, you can either buy one share of WOT, sell any number of shares of WOT that you own, or not
make any transaction at all. What is the maximum profit you can obtain with an optimum trading
strategy?
69
Example
Prices=[1,2]
Buy one share day one, and sell it day two for a profit of 1. Return 1.
Prices[2,1]
No profit can be made so you do not buy or sell stock those days. Return 0.
Function Description
Complete the stockmax function in the editor below.
stockmax has the following parameter(s):
• prices: an array of integers that represent predicted daily stock prices
Returns
• int: the maximum profit achievable
Input Format
The first line contains the number of test cases t.
Each of the next t pairs of lines contain:
- The first line contains an integer n, the number of predicted prices for WOT.
- The next line contains n space-separated integers prices[i], each a predicted stock price for day i.
Constraints
• 1<=t<=10
• 1<=n<=50000
• 1<=prices[i]<=100000
Output Format
Output i lines, each containing the maximum profit that can be obtained for the corresponding test case.
Sample Input
STDIN Function
----- --------
3 q=3
3 prices[] size n = 3
532 prices = [5, 3, 2]
3 prices[] size n = 3
1 2 100 prices = [1, 2, 100]
4 prices[] size n = 4
1312 prices =[1, 3, 1, 2]
Sample Output
0
197
3
Explanation
For the first case, there is no profit because the share price never rises, return 0.
For the second case, buy one share on the first two days and sell both of them on the third day for a profit
of 197.
For the third case, buy one share on day 1, sell one on day 2, buy one share on day 3, and sell one share
on day 4. The overall profit is 3.
70
System.out.println("Maximum Profit: " + maxProfit(prices));
}
return maxProfit;
}
Problem: In what order, n matrices A1, A2, A3, …. An should be multiplied so that it would take a minimum
number of computations to derive the result.
Cost of matrix multiplication: Two matrices are called compatible only if the number of columns in the
first matrix and the number of rows in the second matrix are the same. Matrix multiplication is possible
only if they are compatible. Let A and B be two compatible matrices of dimensions p x q and q x r
Each element of each row of the first matrix is multiplied with corresponding elements of the appropriate
column in the second matrix. The total numbers of multiplications required to multiply matrix A and B are
p x q x r.
71
Counting the number of paranthesization
Let us denote the number of alternative parenthesizations of a sequence of n matrices by p(n). When n =
1, there is only one matrix and therefore only one way to parenthesize the matrix. When n ≥ 2, a fully
parenthesized matrix product is the product of two fully parenthesized matrix sub-products, and the split
between the two subproducts may occur between the k and (k + 1)st matrices for any k = 1, 2, 3…, n – 1.
Thus we obtain the recurrence.
The solution to the recurrence is the sequence of Catalan numbers, which grows as Ω(4n / n3/2), roughly
equal to Ω(2n). Thus, the numbers of solutions are exponential in n. A brute force attempt is infeasible to
find the solution.
Any parenthesizations of the product Ai Ai + 1 … Aj must split the product between Ak and Ak + 1 for some
integer k in the range i ≤ k < j. That is for some value of k, we first compute the matrices A i….k and Ak +
1…j and then multiply them together to produce the final product A i…j The cost of computing these
parenthesizations is the cost of computing Ai….k , plus the cost of computing Ak + 1…j plus the cost of
multiplying them together.
We can define m[i, j] recursively as follows. If i == j, the problem is trivial; the chain consists of only one
matrix Ai…i = A. No scalar multiplications are required. Thus m[i, i] = 0 for i = 1, 2 …n.
To compute m[i, j] when i < j, we take advantage of the structure of an optimal solution of the first step.
Let us assume that the optimal parenthesizations split the product A i Ai + 1…Aj between Ak and Ak + 1, where
i ≤ k < j. Then m[i, j] is equal to the minimum cost for computing the subproducts A i…k and Ak + 1…j plus
the cost of multiplying these two matrices together.
72
static int MatrixChainOrder(int p[], int i, int j)
{
// Write Code Here
…….. ………. ………..
}
// Driver code
public static void main(String args[])
{
int arr[] = new int[] { 1, 2, 3, 4, 3 };
int N = arr.length;
// Function call
System.out.println(
"Minimum number of multiplications is "
+ MatrixChainOrder(arr, 1, N - 1));
}
}
Problem Statement
Given an array of positive distinct integer denoting the crossing time of ‘n’ people. These ‘n’ people are
standing at one side of bridge. Bridge can hold at max two people at a time. When two people cross the
bridge, they must move at the slower person’s pace. Find the minimum total time in which all persons can
cross the bridge.
Note: Slower person space is given by larger time.
Input: Crossing Times = {10, 20, 30}
Output: 60
Explanation
1. Firstly person '1' and '2' cross the bridge
with total time about 20 min(maximum of 10, 20)
2. Now the person '1' will come back with total
time of '10' minutes.
3. Lastly the person '1' and '3' cross the bridge
with total time about 30 minutes
Hence total time incurred in whole journey will be
20 + 10 + 30 = 60
73
1. When any two people cross the bridge, then the fastest person crossing time will not be
contributed in answer as both of them move with slowest person speed.
2. When some of the people will cross the river and reached the right side then only the fastest
people(smallest integer) will come back to the left side.
3. Person can only be present either left side or right side of the bridge. Thus, if we maintain the left
mask, then right mask can easily be calculated by setting the bits ‘1’ which is not present in the
left mask. For instance, Right_mask = ((2n) – 1) XOR (left_mask).
4. Any person can easily be represented by bitmask(usually called as ‘mask’). When i th bit of ‘mask’ is
set, that means that person is present at left side of the bridge otherwise it would be present at
right side of bridge. For instance, let the mask of 6 people is 100101, which represents the person
1, 4, 6 are present at left side of bridge and the person 2, 3 and 5 are present at the right side of
the bridge.
//To find minimum time required to send people on other side of bridge
import java.io.*;
class GFG {
static int dp[][] = new int[1 << 20][2];
public static int findMinTime(int leftmask, boolean turn, int arr[],
int n)
{ // If all people has been transferred
if (leftmask == 0)
return 0;
// Write Code Here
…. ….. …..
else { if (Integer.bitCount(leftmask) == 1) {
for (int i = 0; i < n; ++i) {
// Write Code Here
…. ….. …..
}
// Write Code Here
…. ….. …..}
// Driver Code
public static void main(String[] args)
{
int arr[] = { 10, 20, 30 };
int n = 3;
System.out.print(findTime(arr, n));
}
}
74
9. BackTracking
Backtracking is an algorithmic technique for solving problems recursively by trying to build a
solution incrementally, one piece at a time, removing those solutions that fail to satisfy the
constraints of the problem at any point of time (by time, here, is referred to the time elapsed
till reaching any level of the search tree).
Like all other BackTracking problem, Sudoku can be solved by assigning numbers one by one to empty
cells. Before assigning a number, check whether it is safe to assign.
Check that the same number is not present in the current row, current column and current 3X3 subgrid.
After checking for safety, assign the number, and recursively check whether this assignment leads to a
solution or not. If the assignment doesn’t lead to a solution, then try the next number for the current
empty cell. And if none of the number (1 to 9) leads to a solution, return false and print no solution
exists.
• Create a function that checks after assigning the current index the grid becomes unsafe or not.
Keep Hashmap for a row, column and boxes. If any number has a frequency greater than 1 in
the hashMap return false else return true; hashMap can be avoided by using loops.
75
• Create a recursive function that takes a grid.
• Check for any unassigned location.
• If present then assigns a number from 1 to 9.
• Check if assigning the number to current index makes the grid unsafe or not.
• If safe then recursively call the function for all safe cases from 0 to 9.
• If any recursive call returns true, end the loop and return true. If no recursive call
returns true then return false.
• If there is no unassigned location then return true.
if ((r + 1) % (int)Math.sqrt(N) == 0)
{
System.out.print("");
}
}
}
76
// Driver Code
public static void main(String args[])
{ // Write Code Here
….. ….. ….
};
int N = board.length;
if (solveSudoku(board, N))
{ print(board, N); }
else {
System.out.println("No solution");
}
The eight queens problem is the problem of placing eight queens on an 8×8 chessboard such that none
of them attack one another (no two are in the same row, column, or diagonal). More generally, the n
queens problem places n queens on an n×n chessboard. There are different solutions for the problem.
Explanation:
• This pseudocode uses a backtracking algorithm to find a solution to the 8 Queen problem,
which consists of placing 8 queens on a chessboard in such a way that no two queens threaten
each other.
• The algorithm starts by placing a queen on the first column, then it proceeds to the next column
and places a queen in the first safe row of that column.
• If the algorithm reaches the 8th column and all queens are placed in a safe position, it prints
the board and returns true.
If the algorithm is unable to place a queen in a safe position in a certain column, it backtracks to
the previous column and tries a different row.
• The “isSafe” function checks if it is safe to place a queen on a certain row and column by checking
if there are any queens in the same row, diagonal or anti-diagonal.
• It’s worth to notice that this is just a high-level pseudocode and it might need to be adapted
depending on the specific implementation and language you are using.
77
if not solveNQueens(board, 0):
print("No solution found")
Examples:
ubset sum can also be thought of as a special case of the 0/1 knapsack problem. For each item, there are
two possibilities:
• Include the current element in the subset and recur for the remaining elements with the
remaining Sum.
• Exclude the current element from the subset and recur for the remaining elements.
Finally, if Sum becomes 0 then print the elements of current subset. The recursion’s base case would be
when no items are left, or the sum becomes negative, then simply return.
78
import java.util.ArrayList;
import java.util.List;
public class SubsetSum {
static boolean flag = false;
static void printSubsetSum(int i, int n, int[] set,int targetSum,
List<Integer> subset)
{// Write Code Here
…. …. ….
}
// Driver code
public static void main(String[] args)
{
// Test case 1
int[] set1 = { 1, 2, 1 };
int sum1 = 3;
int n1 = set1.length;
List<Integer> subset1 = new ArrayList<>();
System.out.println("Output 1:");
printSubsetSum(0, n1, set1, sum1, subset1);
System.out.println();
flag = false;
// Test case 2
int[] set2 = { 3, 34, 4, 12, 5, 2 };
int sum2 = 30;
int n2 = set2.length;
List<Integer> subset2 = new ArrayList<>();
System.out.println("Output 2:");
printSubsetSum(0, n2, set2, sum2, subset2);
if (!flag) {
System.out.println("There is no such subset");
}
}
}
Note: Here coloring of a graph means the assignment of colors to all verticesBelow is an example of a
graph that can be colored with 3 different colors:
79
Assign colors one by one to different vertices, starting from vertex 0. Before assigning a color, check for
safety by considering already assigned colors to the adjacent vertices i.e check if the adjacent vertices
have the same color or not. If there is any color assignment that does not violate the conditions, mark the
color assignment as part of the solution. If no assignment of color is possible then backtrack and return
false
Follow the given steps to solve the problem:
• Create a recursive function that takes the graph, current index, number of vertices, and color
array.
• If the current index is equal to the number of vertices. Print the color configuration in the color
array.
• Assign a color to a vertex from the range (1 to m).
• For every assigned color, check if the configuration is safe, (i.e. check if the adjacent vertices do
not have the same color) and recursively call the function with the next index and number of
vertices otherwise, return false
• If any recursive function returns true then return true
• If no recursive function returns true then return false
/* A utility function to check if the current color assignment is safe for vertex v */
boolean isSafe(int v, int graph[][], int color[], int c)
{
// Write Code Here
…. …. …
}
boolean graphColoringUtil(int graph[][], int m, int color[], int v)
{
/* base case: If all vertices are
// Write Code Here
…. …. … }
}
80
return false;
}
// Driver code
public static void main(String args[])
{ // Write Code Here to input Graph
…. …. …
Coloring.graphColoring(graph, m);
}
}
9.5 Hamiltonian Cycle
Hamiltonian Cycle or Circuit in a graph G is a cycle that visits every vertex of G exactly once and returns
to the starting vertex.
If graph contains a Hamiltonian cycle, it is called Hamiltonian graph otherwise it is non-Hamiltonian.
Finding a Hamiltonian Cycle in a graph is a well-known NP Complete Problem, which means that there’s
no known efficient algorithm to solve it for all types of graphs. However, it can be solved for small or
specific types of graphs.
The Hamiltonian Cycle problem has practical applications in various fields, such as logistics, network
design, and computer science.
Hamiltonian Path in a graph G is a path that visits every vertex of G exactly once
and Hamiltonian Path doesn’t have to return to the starting vertex. It’s an open path.
Input: graph[][] = {{0, 1, 0, 1, 0},{1, 0, 1, 1, 1},{0, 1, 0, 0, 1},{1, 1, 0, 0, 1},{0, 1, 1, 1, 0}}
Input graph[][]
81
Output: {0, 1, 2, 4, 3, 0}.
Create an empty path array and add vertex 0 to it. Add other vertices, starting from the vertex 1. Before
adding a vertex, check for whether it is adjacent to the previously added vertex and not already added. If
we find such a vertex, we add the vertex as part of the solution. If we do not find a vertex then we
return false.
82
10. Backtracking
10.1 Partition of a set into K subsets with equal sum
Output : Yes
Output : No
It is not possible to divide above array into 3 parts with equal sum
// Java program to check whether an array can be partitioned into K subsets of equal sum
class GFG
{
Static boolean isKPartitionPossibleRec(int arr[], int subsetSum[], boolean taken[],
int subset, int K, int N, int curIdx, int limitIdx)
{
// Write Code Here
…. …. …
}
}
return false;
83
}
// Method returns true if arr can be partitioned into K subsets with equal sum
static boolean isKPartitionPossible(int arr[], int N, int K)
{ // Write Code Here
…. …. …
}
// Driver code
public static void main(String[] args)
{
int arr[] = {2, 1, 4, 5, 3, 3};
int N = arr.length;
int K = 3;
if (isKPartitionPossible(arr, N, K))
System.out.println("Partitions into equal sum is possible.");
else
System.out.println("Partitions into equal sum is not possible.");
}
}
Given two strings, the task is to print all the longest common sub-sequences in lexicographical order.
Examples:
Output: ababa
abaca
abcba
acaba
acaca
acbaa
acbca
This problem is an extension of longest common subsequence, We first find the length of LCS and store
all LCS in a 2D table using Memoization (or Dynamic Programming). Then we search all characters from ‘a’
to ‘z’ (to output sorted order) in both strings. If a character is found in both strings and the current
positions of the character lead to LCS, we recursively search all occurrences with current LCS length plus
1.
84
// Java program to find all LCS of two strings in sorted order.
import java.io.*;
class GFG
{
static int MAX = 100;
static int lcslen = 0;
static int[][] dp = new int[MAX][MAX];
static int lcs(String str1, String str2, int len1, int len2, int i, int j)
{ // Write Code Here
… …. …
}
static void printAll(String str1, String str2, int len1, int len2, char[] data, int indx1, int indx2,
int currlcs)
{ // Write Code Here
… …. …
}
// Driver code
public static void main(String[] args)
{
String str1 = "abcabcaa", str2 = "acbacba";
prinlAllLCSSorted(str1, str2);
}
}
10.3 Print all Palindromic Partitions of a String using Bit Manipulation
85
• Each of these positions can be given a binary number 1 (If a cut is made in this position) or 0 (If
no cut is made in this position).
• This will give a total of 2n-1 partitions and for each partition check whether this partition is
palindrome or not.
import java.util.ArrayList;
import java.util.List;
class GFG {
List<List<String>> ans = new ArrayList<>();
boolean checkPalindrome(List<String> currPartition) {
// Write Code Here
…. … ..
}
return true;
}
void generatePartition(String s, String bitString) {
// Write Code Here
…. … ..
}
void bitManipulation(String s, String bitString) {
// Write Code Here
…. … ..
}
Given a path in the form of a rectangular matrix having few landmines arbitrarily placed (marked as 0),
calculate length of the shortest safe route possible from any cell in the first column to any cell in the last
column of the matrix. We have to avoid landmines and their four adjacent cells (left, right, above and
below) as they are also unsafe. We are allowed to move to only adjacent cells which are not landmines. i.e.
the route cannot contains any diagonal moves.
Examples:
Input:
A 12 x 10 matrix with landmines marked as 0
[1 1 1 1 1 1 1 1 1 1]
[1 0 1 1 1 1 1 1 1 1]
86
[1 1 1 0 1 1 1 1 1 1]
[1 1 1 1 0 1 1 1 1 1]
[1 1 1 1 1 1 1 1 1 1]
[1 1 1 1 1 0 1 1 1 1]
[1 0 1 1 1 1 1 1 0 1]
[1 1 1 1 1 1 1 1 1 1]
[1 1 1 1 1 1 1 1 1 1]
[0 1 1 1 1 0 1 1 1 1]
[1 1 1 1 1 1 1 1 1 1]
[1 1 1 0 1 1 1 1 1 1]
Output:
Length of shortest safe route is 13 (Highlighted in Bold)
The idea is to use Backtracking. We first mark all adjacent cells of the landmines as unsafe. Then for each
safe cell of first column of the matrix, we move forward in all allowed directions and recursively checks if
they leads to the destination or not. If destination is found, we update the value of shortest path else if
none of the above solutions work we return false from our function.
// Java program to find shortest safe Route in the matrix with landmines
import java.util.Arrays;
class GFG{
static final int R = 12;
static final int C = 10;
static int rowNum[] = { -1, 0, 0, 1 };
static int colNum[] = { 0, -1, 1, 0 };
static int min_dist;
// A function to check if a given cell (x, y) can be visited or not
static boolean isSafe(int[][] mat, boolean[][] visited, int x, int y)
{
// Write Code Here
…. …. ….}
// A function to check if a given cell (x, y) is// a valid cell or not
static boolean isValid(int x, int y)
{
// Write Code Here
…. …. ….}
static void markUnsafeCells(int[][] mat)
{ // Write Code Here
…. …. ….
}
static void findShortestPathUtil(int[][] mat, boolean[][] visited, int i, int j, int dist)
{ // Write Code Here
…. …. ….
}
87
// A wrapper function over findshortestPathUtil()
static void findShortestPath(int[][] mat)
{ // Write Code Here
…. …. ….
}
// Driver code
public static void main(String[] args)
{ // Input matrix with landmines shown with number 0
// Write Code Here
…. …. ….
findShortestPath(mat);
}
}
Problem Statement
Given a valid sentence without any spaces between the words and a dictionary of valid English words, find
all possible ways to break the sentence into individual dictionary words.
Example:
Consider the following dictionary
{ i, like, sam, sung, samsung, mobile, ice,
and, cream, icecream, man, go, mango}
Input: "ilikesamsungmobile"
Output: i like sam sung mobile
i like samsung mobile
Input: "ilikeicecreamandmango"
Output: i like ice cream and man go
i like ice cream and mango
i like icecream and man go
88
static void wordBreakUtil(int n, String s, List<String> dict, String ans)
{
// Write code here
…. …. ….
}
// main function
public static void main(String args[])
{ //Input str1 and str2
// Write code here
…. …. ….
wordBreak(n1,dict,str1);
System.out.println("\nSecond Test:");
wordBreak(n2,dict,str2);
}
}
89
For example, consider the graph shown in figure on right side. A TSP tour in the graph is 0-1-3-2-0. The
cost of the tour is 10+25+30+15 which is 80.
Branch and Bound Solution
As seen in the previous articles, in Branch and Bound method, for current node in tree, we compute a
bound on best possible solution that we can get if we down this node. If the bound on best possible
solution itself is worse than current best (best computed so far), then we ignore the subtree rooted with
the node.
Note that the cost through a node includes two costs.
1) Cost of reaching the node from the root (When we reach a node, we have this cost computed)
2) Cost of reaching an answer from current node to a leaf (We compute a bound on this cost to decide
whether to ignore subtree with this node or not).
• In cases of a maximization problem, an upper bound tells us the maximum possible solution if
we follow the given node.
• In cases of a minimization problem, a lower bound tells us the minimum possible solution if we
follow the given node.
In branch and bound, the challenging part is figuring out a way to compute a bound on best possible
solution. Below is an idea used to compute bounds for Travelling salesman problem.
Cost of any tour can be written as below.
Cost of a tour T = (1/2) * ? (Sum of cost of two edges adjacent to u and in the tour T)
where u ? V
For every vertex u, if we consider two edges through it in T, and sum their costs. The overall sum for all
vertices would be twice of cost of tour T (We have considered every edge twice.)
(Sum of two tour edges adjacent to u) >= (sum of minimum weight two edges adjacent to u)
Cost of any tour >= 1/2) * ? (Sum of cost of two minimum weight edges adjacent to u)
where u ? V
Now we have an idea about computation of lower bound. Let us see how to how to apply it state space
search tree. We start enumerating all possible nodes (preferably in lexicographical order)
1. The Root Node: Without loss of generality, we assume we start at vertex “0” for which the lower bound
has been calculated above.
Dealing with Level 2: The next level enumerates all possible vertices we can go to (keeping in mind that
in any path a vertex has to occur only once) which are, 1, 2, 3… n (Note that the graph is complete).
Consider we are calculating for vertex 1, Since we moved from 0 to 1, our tour has now included the edge
0-1. This allows us to make necessary changes in the lower bound of the root.
90
Lower Bound for vertex 1 =
Old lower bound - ((minimum edge cost of 0 + minimum edge cost of 1) / 2)
+ (edge cost 0-1)
How does it work? To include edge 0-1, we add the edge cost of 0-1, and subtract an edge weight such
that the lower bound remains as tight as possible which would be the sum of the minimum edges of 0
and 1 divided by 2. Clearly, the edge subtracted can’t be smaller than this.
Dealing with other levels: As we move on to the next level, we again enumerate all possible vertices. For
the above case going further after 1, we check out for 2, 3, 4, …n.
Consider lower bound for 2 as we moved from 1 to 1, we include the edge 1-2 to the tour and alter the
new lower bound for this node.
Lower bound(2) = Old lower bound - ((second minimum edge cost of 1 + minimum edge cost of 2)/2)
+ edge cost 1-2)
Note: The only change in the formula is that this time we have included second minimum edge cost for 1,
because the minimum edge cost has already been subtracted in previous level.
// Java program to solve Traveling Salesman Problem using Branch and Bound.
import java.util.*;
class GFG
{ static int N = 4;
static int final_path[] = new int[N + 1];
static boolean visited[] = new boolean[N];
static int final_res = Integer.MAX_VALUE;
static void copyToFinal(int curr_path[])
{ // Write Code Here
… …. ….
}
// Function to find the minimum edge cost having an end at the vertex i
static int firstMin(int adj[][], int i)
{
// Write Code Here
… …. ….}
static int secondMin(int adj[][], int i)
{
// Write Code Here
… …. ….
}
static void TSPRec(int adj[][], int curr_bound, int curr_weight, int level, int curr_path[])
{ // Write Code Here
… …. …. }
91
// Driver code
public static void main(String[] args)
{
//Adjacency matrix for the given graph
// Write Code Here
… …. ….
TSP(adj);
System.out.printf("Minimum cost : %d\n", final_res);
System.out.printf("Path Taken : ");
for (int i = 0; i <= N; i++)
{
System.out.printf("%d ", final_path[i]);
}
}
}
Let there be N workers and N jobs. Any worker can be assigned to perform any job, incurring some cost
that may vary depending on the work-job assignment. It is required to perform all jobs by assigning
exactly one worker to each job and exactly one job to each agent in such a way that the total cost of the
assignment is minimized.
92
There are two approaches to calculate the cost function:
1. For each worker, we choose job with minimum cost from list of unassigned jobs (take minimum
entry from each row).
2. For each job, we choose a worker with lowest cost for that job from list of unassigned workers
(take minimum entry from each column).
Below diagram shows complete search space diagram showing optimal solution path in green.
Complete Algorithm:
/* findMinCost uses Least() and Add() to maintain the list of live nodes
Least() finds a live node with least cost, deletes it from the list and returns it
Add(x) calculates cost of x and adds it to the list of live nodes
Implements list of live nodes as a min heap */
// Search Space Tree Node node
{
int job_number;
int worker_number;
node parent;
int cost;
}
// Input: Cost Matrix of Job Assignment problem Output: Optimal cost and Assignment of Jobs
algorithm findMinCost (costMatrix mat[][])
{
// Initialize list of live nodes(min-Heap) with root of search tree i.e. a Dummy node
while (true)
{
// Find a live node with least estimated cost
E = Least();
// The found node is deleted from the list of live nodes
if (E is a leaf node)
{
93
printSolution();
return;
}
import java.util.*;
// Node class represents a job assignment
class Node {
Node parent; // parent node
int pathCost; // cost to reach this node
int cost; // lower bound cost
int workerID; // worker ID
int jobID; // job ID
boolean assigned[]; // keeps track of assigned jobs
public Node(int N) {
assigned = new boolean[N]; // initialize assigned jobs array
}
}
public class Main {
static final int N = 4; // number of workers and jobs
94
static void printAssignments(Node min) {
// Write Code Here
…. ….. … }
// Function to solve Job Assignment Problem using Branch and Bound
static int findMinCost(int costMatrix[][]) {
// Write Code Here
…. ….. … }
Since, we have to place 4 queens such as q 1 q2 q3 and q4 on the chessboard, such that no two queens
attack each other. In such a conditional each queen must be placed on a different row, i.e., we put queen
"i" on row "i."
Now, we place queen q1 in the very first acceptable position (1, 1). Next, we put queen q 2 so that both
these queens do not attack each other. We find that if we place q2 in column 1 and 2, then the dead end
is encountered. Thus the first acceptable position for q 2 in column 3, i.e. (2, 3) but then no position is left
for placing queen 'q3' safely. So we backtrack one step and place the queen 'q 2' in (2, 4), the next best
possible solution. Then we obtain the position for placing 'q3' which is (3, 2). But later this position also
leads to a dead end, and no place is found where 'q4' can be placed safely. Then we have to backtrack till
'q1' and place it to (1, 2) and then all other queens are placed safely by moving q 2 to (2, 4), q3 to (3, 1) and
q4 to (4, 3). That is, we get the solution (2, 4, 1, 3). This is one possible solution for the 4-queens problem.
For another possible solution, the whole method is repeated for all partial solutions. The other solutions
for 4 - queens problems is (3, 1, 4, 2) i.e.
95
The implicit tree for 4 - queen problem for a solution (2, 4, 1, 3) is as follows:
Place (k, i) returns a Boolean value that is true if the kth queen can be placed in column i. It tests
both whether i is distinct from all previous costs x1, x2,....xk-1 and whether there is no other queen
on the same diagonal.
Using place, we give a precise solution to then n- queens problem.
1. Place (k, i)
2. {
3. For j ← 1 to k - 1
4. do if (x [j] = i)
5. or (Abs x [j]) - i) = (Abs (j - k))
6. then return false;
7. return true;
8. }
Place (k, i) return true if a queen can be placed in the kth row and ith column otherwise return is false.
x [] is a global array whose final k - 1 values have been set. Abs (r) returns the absolute value of r.
1. N - Queens (k, n)
2. {
3. For i ← 1 to n
4. do if Place (k, i) then
5. {
6. x [k] ← i;
7. if (k ==n) then
8. write (x [1....n));
9. else
10. N - Queens (k + 1, n);
11. }
96
12. }
Given two arrays v[] and w[] that represent values and weights associated with n items respectively. Find
out the maximum value subset(Maximum Profit) of v[] such that the sum of the weights of this subset is
smaller than or equal to Knapsack capacity Cap(W).
Note: The constraint here is we can either put an item completely into the bag or cannot put it at all. It is
not possible to put a part of an item into the bag.
97
Implementation of 0/1 Knapsack using Branch and Bound
The idea is to use the fact that the Greedy algorithm provides the best solution for Fractional Knapsack
problem. To check if a particular node can give us a better solution or not, we compute the optimal
solution (through the node) using Greedy approach. If the solution computed by Greedy approach itself is
more than the best so far, then we can’t get a better solution through the node.
Algorithm:
• Sort all items in decreasing order of ratio of value per unit weight so that an upper bound can be
computed using Greedy Approach.
• Create a dummy node of decision tree and enqueue it to Q. Profit and weight of dummy node are
0.
• Compute profit of next level node. If the profit is more than maxProfit, then update
maxProfit.
98
• Compute bound of next level node. If bound is more than maxProfit, then add next level
node to Q.
• Consider the case when next level node is not considered as part of solution and add a
node to queue with level as next, but weight and profit without considering next level
nodes.
import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;
class Item {
float weight;
int value;
Item(float weight, int value) {
this.weight = weight;
this.value = value;
}
}
class Node {
int level, profit, bound;
float weight;
99
new Item(1.98f, 100),
new Item(5, 95),
new Item(3, 30)
};
int n = arr.length;
int maxProfit = knapsack(W, arr, n);
System.out.println("Maximum possible profit = " +
maxProfit);
}
}
By avoiding searching in sub-trees which do not include an answer node, an "intelligent" ranking
function, also known as an approximation costs function, may frequently speed up the search for an
answer node.
A live node is a created node whose children have not yet been formed.
100
The offspring of the E-node which is a live node, are now being investigated. Or to put it another way, an
E-node is a node that is currently expanding.
A created node which is not to be developed or examined further is referred to as a dead node. A dead
node has already extended all of its offspring.
Cost function:
In the search tree, each node Y has a corresponding cost. The next E-node may be found using the cost
function. The E-node with the lowest costs is the next one. The function can be defined as:
We suppose that it will costs one unit to move a tile in any direction. In light of this, we create the following
costs function for the 8-puzzle algorithm:
h(y) = the amount of the non-blank tiles which are not in their final goal position (misplaced tiles).
To change state y into a desired state, there are at least h(y) movements required.
There is an algorithm for estimating the unknown value of h(y), which is accessible.
Final algorithm:
In order to maintain the list of live nodes, algorithm LCSearch employs the functions Least() and Add().
Least() identifies a live node with the least c(y), removes it from the list, and returns it.
Add(y) adds y to the list of live nodes.
Add(y) implements the list of live nodes as a min-heap.
The route taken by the aforementioned algorithm to arrive at the final configuration of the 8-Puzzle from
the starting configuration supplied is shown in the diagram below. Keep in mind that only nodes with
the lowest costs function value are extended.
101
// Java Program to print path from root node to destination node for N*N -1 puzzle
// algorithm using Branch and Bound The solution assumes that instance of puzzle is olvable
import java.io.*;
import java.util.*;
class GFG
{ public static int N = 3;
public static class Node
{ // Code Here
… … …}
// Function to print N x N matrix
public static void printMatrix(int mat[][]){
// Code Here
… … …}
// Function to allocate a new node
public static Node newNode(int mat[][], int x, int y,….
// Code Here
… … …}
102
public static void solve(int initialMat[][], int x, int y, int finalMat[][])
{
// Code Here
… … … }
//Driver Code
public static void main (String[] args)
{
// Code Here for input
… … …
solve(initialMat, x, y, finalMat);
}
}
Examples:
Input: N = 3
Input: N = 2
Output: 00 01 10 11
103
import java.util.*;
// Creating a Node class
class Node {
int soln[];
int level;
ArrayList<Node> child;
Node parent;
Node(Node parent, int level, int N)
{
this.parent = parent;
this.level = level;
this.soln = new int[N];
}
}
class GFG {
// Write Code Here
… … … }
// Driver code
public static void main(String args[])
{
N = 3;
Node root = new Node(null, 0, N);
Q = new LinkedList<Node>();
Q.add(root);
while (Q.size() != 0) {
Node E = Q.poll();
generate(E);
}
}
}
A Feature selection is critical in the domains of machine learning and data analysis since it assists in
identifying the most essential and informative features in a dataset. It is a procedure that seeks to extract
relevant features that will help with analysis and modelling jobs. The branch and bound method is an
effective feature selection tool. −
As the volume of data grows at an exponential rate, it is becoming increasingly vital to build efficient
algorithms capable of quickly identifying the ideal subset of attributes. In this post, we will look at feature
selection and how the branch and bound method may be used to improve the efficiency and accuracy of
the feature selection process.
104
What is Feature Selection?
In machine learning and statistics, feature selection refers to the process of choosing a subset of relevant
features that are most informative for a given task. By selecting the right features, we aim to improve the
model's performance, reduce computational complexity, and mitigate the risk of overfitting.
Significance of Feature Selection
Feature selection offers several advantages in the field of data analysis and machine learning −
• Improved Model Performance − By selecting the most relevant features, we can enhance the
accuracy and predictive power of the model. Irrelevant or redundant features can introduce noise
and hinder model performance.
• Reduced Dimensionality − Feature selection helps in reducing the number of dimensions or
attributes in the dataset. This reduction simplifies the problem space, improves computational
efficiency, and facilitates better model interpretability.
• Elimination of Overfitting − Including irrelevant features in the model can lead to overfitting,
where the model becomes too specific to the training data and fails to generalize well on unseen
data. Feature selection mitigates this risk by focusing on the most informative features.
• Faster Training and Inference − By reducing the dimensionality of the dataset, feature selection
can significantly speed up the training and inference phases of the model. This is particularly
important when dealing with large-scale datasets.
What is Branch and Bound Algorithm?
The Branch and Bound algorithm is a systematic approach to finding the optimal subset of features by
exploring all possible feature combinations. It utilizes a divide-and-conquer strategy coupled with
intelligent pruning to efficiently search the feature space. The algorithm begins with an initial bound and
progressively explores different branches to narrow down the search space until the optimal subset is
found.
Algorithm
Step 1: Initialization
The Branch and Bound algorithm starts by initializing the search process. This involves setting up the
initial bounds, creating a priority queue to track the best feature subsets, and defining other necessary
data structures.
Step 2: Generate Initial Bounds
To guide the search process, the algorithm generates initial bounds based on the evaluation criteria.
These bounds provide an estimate of the best possible solution and help in pruning unpromising
branches.
Step 3: Explore Branches
The algorithm explores different branches or paths in the search tree. Each branch represents a subset of
features. It evaluates the quality of each branch based on a predefined evaluation metric and decides
whether to further explore or prune the branch.
Step 4: Update Bounds
As the algorithm progresses and explores different branches, it updates the bounds dynamically. This
allows for more accurate pruning decisions and helps in speeding up the search process.
Step 5: Pruning and Stopping Criteria
105
Branch and Bound employ pruning techniques to eliminate branches that are guaranteed to be
suboptimal. This reduces the search space and focuses on more promising feature subsets. The algorithm
continues the search until a stopping criterion is met, such as finding the optimal subset or reaching a
predefined computational limit.
Example Demonstration
Let's consider a simple example to illustrate the working of the Branch and Bound algorithm. Suppose we
have a dataset with 10 features, and we want to find the optimal subset of features for a classification
task. The algorithm would systematically explore different feature combinations, evaluate their
performance, and prune unpromising branches until it discovers the subset with the highest evaluation
metrics, such as accuracy or information gain.
Example
Below is the program for the above example −
import itertools
def evaluate_subset(subset):
return len(subset)
def branch_and_bound(features, k):
n = len(features)
best_subset = []
best_score = 0.0
def evaluate_branch(subset):
Write Code Here
………………..
def backtrack(subset, idx):
Write Code Here
………………..
return best_subset
# Example usage
if __name__ == '__main__':
features = ['Feature A', 'Feature B', 'Feature C', 'FeatureD', 'Feature E', 'Feature F', 'Feature G', 'Feature
H', 'Feature I', 'Feature J']
k = 3 # Number of features to select
selected_features = branch_and_bound(features, k)
print(f"Selected Features: {selected_features}")
106
12.3 Mixed Integer Programming (MIP) using Branch and bound
Problem Statement:
Imagine you are the owner of a cat shelter. Every day, pet owners can bring their cats and you take care of
them. Many people adopted a cat during COVID, but now everyone needs to be back at the office. Because
of this your company is doing great.
Actually, a bit too great. You are having difficulties with placing all the cats in the rooms of your building.
Sometimes you need to decline people because there are too many requests. That is why you decided to
create an optimization algorithm to help you find the lowest number of rooms possible for all the cat
registrations.
Let’s take a look at an example. Imagine that 3 cats requested to stay at your shelter. Their names are Lily,
Charlie, and Meowster. How can we divide these three cats in different rooms? We need at most three
rooms, and here are all the possible solutions of grouping the cats:
Partitions of cats
Partitions and the Bell number
As you can see, there are 5 possible ways to group the 3 cats. In math, the name for one way of grouping
elements of a set is a partition. The Bell number corresponds to the total number of possible partitions for
a given set (in our case, with the three cats we can create 5 partitions). It’s from the field of combinatorics.
The recursive formula for calculating the next Bell number looks like this:
107
Recursive formula for calculating the Bell number. Image by author.
This number increases rapidly:
import org.apache.commons.math3.optim.linear.LinearObjectiveFunction;
import org.apache.commons.math3.optim.linear.Relationship;
import org.apache.commons.math3.optim.linear.LinearConstraint;
import org.apache.commons.math3.optim.linear.NoFeasibleSolutionException;
import org.apache.commons.math3.optim.linear.SimplexSolver;
import org.apache.commons.math3.optim.linear.NonNegativeConstraint;
import org.apache.commons.math3.optim.linear.UnboundedSolutionException;
import org.apache.commons.math3.optim.MaxIter;
import org.apache.commons.math3.optim.OptimizationData;
import java.util.ArrayList;
import java.util.List;
public class MIPSolver {
public static void main(String[] args) {
// Write Code Here
…. …. …
};
try {
SimplexSolver solver = new SimplexSolver();
double[] solution = solver.optimize(f, constraints, optData).getPoint();
System.out.println("Optimal solution: x1 = " + solution[0] + ", x2 = " + solution[1]);
} catch (NoFeasibleSolutionException e) {
System.out.println("No feasible solution found.");
} catch (UnboundedSolutionException e) {
System.out.println("Solution is unbounded.");
}
}
}
108
Let’s start with a Cat class.
import random
from typing import List
import numpy as np
class Cat:
"""
A cat has a name, a weight and a character.
"""
import time
from typing import List
from cat_generator import Cat, generate_n_cats
class Node:
def __init__(self, partition, remaining_cats, score):
self.partition = partition
self.remaining_cats = remaining_cats
self.score = score
def is_feasible(self):
Write Code Here
………..
return True
def calculate_lower_bound(self):
Write Code Here
………………………
return lower_bound
109
@staticmethod
def calculate_weight(group):
"""
Calculate the weight of a group.
"""
return sum([cat.weight for cat in group])
@staticmethod
def count_angry_cats(group):
"""
Check how many angry cats are in a group.
"""
angry_cats = [cat for cat in group if cat.character == "angry"]
return len(angry_cats)
class BranchAndBound:
def __init__(self, cats: List[Cat]) -> None:
self.cats = cats
self.solution_type = "Branch and Bound"
The task is to generate a binary string of length N using branch and bound technique Examples:
Input: N = 3 Output: 000 001 010 011 100 101 110 111 Explanation: Numbers with 3 binary digits are 0,
1, 2, 3, 4, 5, 6, 7 Input: N = 2 Output: 00 01 10 11
Approach: Generate Combinations using Branch and Bound:
110
• It starts with an empty solution vector.
• While Queue is not empty remove partial vector from queue.
• If it is a final vector print the combination else,
• For the next component of partial vector create k child vectors by fixing all possible states for the
next component insert vectors into the queue.
Below is the implementation of the above approach
class GFG {
// Write Code Here
… … … }
// Driver code
public static void main(String args[])
{
N = 3;
Node root = new Node(null, 0, N);
Q = new LinkedList<Node>();
Q.add(root);
while (Q.size() != 0) {
Node E = Q.poll();
generate(E);
}
}
}
111
12.5 A* Search Algorithm
Motivation
To approximate the shortest path in real-life situations, like- in maps, games where there can be many
hindrances.
We can consider a 2D Grid having several obstacles and we start from a source cell (colored red below) to
reach towards a goal cell (colored green below)
112
way (walls, water, etc.). There can be many ways to calculate this ‘h’ which are discussed in the later
sections.
Algorithm
We create two lists – Open List and Closed List (just like Dijkstra Algorithm)
// A* Search Algorithm
1. Initialize the open list
2. Initialize the closed list
put the starting node on the open
list (you can leave its f at zero)
3. while the open list is not empty
a) find the node with the least f on
the open list, call it "q"
b) pop q off the open list
113
So suppose as in the below figure if we want to reach the target cell from the source cell, then the A*
Search algorithm would follow path as shown below. Note that the below figure is made by
considering Euclidean Distance as a heuristics.
Heuristics
We can calculate g but how to calculate h ?
We can do things.
A) Either calculate the exact value of h (which is certainly time consuming).
OR
B ) Approximate the value of h using some heuristics (less time consuming).
We will discuss both of the methods.
A) Exact Heuristics –
We can find exact values of h, but that is generally very time consuming.
Below are some of the methods to calculate the exact value of h.
1) Pre-compute the distance between each pair of cells before running the A* Search Algorithm.
2) If there are no blocked cells/obstacles then we can just find the exact value of h without any pre-
computation using the distance formula/Euclidean Distance
B) Approximation Heuristics –
There are generally three approximation heuristics to calculate h –
1) Manhattan Distance –
• It is nothing but the sum of absolute values of differences in the goal’s x and y coordinates and
the current cell’s x and y coordinates respectively, i.e.,
114
h = abs (current_cell.x – goal.x) +
abs (current_cell.y – goal.y)
• When to use this heuristic? – When we are allowed to move only in four directions only (right, left,
top, bottom)
The Manhattan Distance Heuristics is shown by the below figure (assume red spot as source cell and
green spot as target cell).
2) Diagonal Distance-
• It is nothing but the maximum of absolute values of differences in the goal’s x and y coordinates
and the current cell’s x and y coordinates respectively, i.e.,
dx = abs(current_cell.x – goal.x)
dy = abs(current_cell.y – goal.y)
• When to use this heuristic? – When we are allowed to move in eight directions only (similar to a
move of a King in Chess)
The Diagonal Distance Heuristics is shown by the below figure (assume red spot as source cell and
green spot as target cell).
3) Euclidean Distance-
• As it is clear from its name, it is nothing but the distance between the current cell and the goal
cell using the distance formula
115
h = sqrt ( (current_cell.x – goal.x)2 +
(current_cell.y – goal.y)2 )
• When to use this heuristic? – When we are allowed to move in any directions.
The Euclidean Distance Heuristics is shown by the below figure (assume red spot as source cell and
green spot as target cell).
import java.util.*;
class Node {
int x, y;
int g, h;
Node parent;
public Node(int x, int y) {
this.x = x;
this.y = y;
}
public int getF() {
return g + h;
}
}
116
public static int heuristic(int x, int y, int tx, int ty) {
return Math.abs(tx - x) + Math.abs(ty - y);
}
public static List<Node> astar(int[][] grid, int sx, int sy, int tx, int ty) {
// Write code Here
…. …. .. }
return null; // No path found
}
if (path != null) {
System.out.println("Path found:");
for (int i = path.size() - 1; i >= 0; i--) {
Node node = path.get(i);
System.out.println("(" + node.x + ", " + node.y + ")");
}
} else {
System.out.println("No path found.");
}
}
}
Topological sorting for Directed Acyclic Graph (DAG) is a linear ordering of vertices such that for every
directed edge u-v, vertex u comes before v in the ordering.
Note: Topological Sorting for a graph is not possible if the graph is not a DAG.
Example:
Input: Graph
117
Output: 5 4 2 3 1 0
Explanation: The first vertex in topological sorting is always a vertex with an in-degree of 0 (a vertex with
no incoming edges). A topological sorting of the following graph is “5 4 2 3 1 0”. There can be more than
one topological sorting for a graph. Another topological sorting of the following graph is “4 5 2 3 1 0”
Approach:
118
System.out.print(stack.pop() + " ");
}
}
// Driver code
public static void main(String[] args)
{
// Number of nodes
int V = 4;
// Edges
List<List<Integer> > edges = new ArrayList<>();
edges.add(Arrays.asList(0, 1));
edges.add(Arrays.asList(1, 2));
edges.add(Arrays.asList(3, 1));
edges.add(Arrays.asList(3, 2));
topologicalSort(adj, V);
}
}
Given n cities and distances between every pair of cities, select k cities to place warehouses (or ATMs or
The following is a description of the instance of this famous puzzle involving N = 2 eggs and a building
with K = 36 floors.
Suppose that we wish to know which stories in a 36-story building are safe to drop eggs from, and which
will cause the eggs to break on landing. We make a few assumptions:
• An egg that survives a fall can be used again.
• A broken egg must be discarded.
• The effect of a fall is the same for all eggs.
• If an egg breaks when dropped, then it would break if dropped from a higher floor.
• If an egg survives a fall then it would survive a shorter fall.
• It is not ruled out that the first-floor windows break eggs, nor is it ruled out that the 36th-floor
does not cause an egg to break.
If only one egg is available and we wish to be sure of obtaining the right result, the experiment can be
carried out in only one way. Drop the egg from the first-floor window; if it survives, drop it from the
119
second-floor window. Continue upward until it breaks. In the worst case, this method may require 36
droppings. Suppose 2 eggs are available. What is the least number of egg droppings that are guaranteed
to work in all cases?
The problem is not actually to find the critical floor, but merely to decide floors from which eggs should
be dropped so that the total number of trials is minimized.
The solution is to try dropping an egg from every floor(from 1 to K) and recursively calculate the
minimum number of droppings needed in the worst case. The floor which gives the minimum value in the
worst case is going to be part of the solution.
In the following solutions, we return the minimum number of trials in the worst case; these solutions can
be easily modified to print the floor numbers of every trial also.
What is worst case scenario?
Worst case scenario gives the user the surety of the threshold floor. For example- If we have ‘1’ egg and
‘K’ floors, we will start dropping the egg from the first floor till the egg breaks suppose on the ‘Kth’ floor
so the number of tries to give us surety is ‘K’.
To solve the problem follow the below idea:
Since the same subproblems are called again, this problem has the Overlapping Subproblems property.
So Egg Dropping Puzzle has both properties of a dynamic programming problem. Like other typical DP
problem, re-computations of the same subproblems can be avoided by constructing a temporary array
eggFloor[][] in a bottom-up manner.
In this approach, we work on the same idea as described above neglecting the case of calculating the
answers to sub-problems again and again. The approach will be to make a table that will store the results
of sub-problems so that to solve a sub-problem, would only require a look-up from the table which will
take constant time, which earlier took exponential time.
Formally for filling DP[i][j] state where ‘i’ is the number of eggs and ‘j’ is the number of floors:
We have to traverse for each floor ‘x’ from ‘1’ to ‘j’ and find a minimum of:
(1 + max( DP[i-1][j-1], DP[i][j-x] )).
Below is the illustration of the above approach:
i => Number of eggs
j => Number of floors
Look up find maximum
Lets fill the table for the following case:
Floors = ‘4’
Eggs = ‘2’
1234
1 2 3 4 => 1
1 2 2 3 => 2
For ‘egg-1’ each case is the base case so the
number of attempts is equal to floor number.
For ‘egg-2’ it will take ‘1’ attempt for 1st
floor which is base case.
For floor-2 =>
Taking 1st floor 1 + max(0, DP[1][1])
120
Taking 2nd floor 1 + max(DP[1][1], 0)
DP[2][2] = min(1 + max(0, DP[1][1]), 1 + max(DP[1][1], 0))
For floor-3 =>
Taking 1st floor 1 + max(0, DP[2][2])
Taking 2nd floor 1 + max(DP[1][1], DP[2][1])
Taking 3rd floor 1 + max(0, DP[2][2])
DP[2][3]= min(‘all three floors’) = 2
For floor-4 =>
Taking 1st floor 1 + max(0, DP[2][3])
Taking 2nd floor 1 + max(DP[1][1], DP[2][2])
Taking 3rd floor 1 + max(DP[1][2], DP[2][1])
Taking 4th floor 1 + max(0, DP[2][3])
DP[2][4]= min(‘all four floors’) = 3
import java.io.*;
class EggDrop {
/* Driver code */
public static void main(String args[])
{
int n = 2, k = 36;
System.out.println(
"Minimum number of trials in worst"
+ " case with " + n + " eggs and " + k
+ " floors is " + eggDrop(n, k));
}
}
121
13.3 Policemen Catch Thieves
122
System.out.println("Maximum thieves caught: " + policeThief(arr2, n, k));
Given length of wall w and shelves of two lengths m and n, find the number of each type of shelf to be
used and the remaining empty space in the optimal solution so that the empty space is minimum. The
larger of the two shelves is cheaper so it is preferred. However cost is secondary and first priority is to
minimize empty space on wall.
A simple and efficient approach will be to try all possible combinations of shelves that fit within the length
of the wall.
To implement this approach along with the constraint that larger shelf costs less than the smaller one,
starting from 0, we increase no of larger type shelves till they can be fit. For each case we calculate the
empty space and finally store that value which minimizes the empty space. if empty space is same in two
cases we prefer the one with more no of larger shelves.
// Driver Code
public static void main(String[] args)
{
123
int wall = 24, m = 3, n = 5;
minSpacePreferLarge(wall, m, n);
wall = 24;
m = 4;
n = 7;
minSpacePreferLarge(wall, m, n);
}
}
The only way to learn Design and Analyzing algorithm is writing algorithms for solving real time applications
and challenging problems optimally through programming. The problems in this tutorial are certainly NOT
challenging. There are tens of thousands of challenging problems available – used in training for various
programming contests (such as International Collegiate Programming Contest (ICPC), International
Olympiad in Informatics (IOI)). Check out these sites:
• The ACM - ICPC International collegiate programming contest (https://icpc.global/ )
• The Topcoder Open (TCO) annual programming and design contest (https://www.topcoder.com/ )
• Universidad de Valladolid’s online judge (https://uva.onlinejudge.org/ ).
• Peking University’s online judge (http://poj.org/ ).
• USA Computing Olympiad (USACO) Training Program @ http://train.usaco.org/usacogate.
• Google’s coding competitions (https://codingcompetitions.withgoogle.com/codejam,
https://codingcompetitions.withgoogle.com/hashcode )
• The ICFP programming contest (https://www.icfpconference.org/ )
• BME International 24-hours programming contest (https://www.challenge24.org/ )
• The International Obfuscated C Code Contest (https://www0.us.ioccc.org/main.html )
• Internet Problem Solving Contest (https://ipsc.ksp.sk/ )
• Microsoft Imagine Cup (https://imaginecup.microsoft.com/en-us )
• Hewlett Packard Enterprise (HPE) Codewars (https://hpecodewars.org/ )
• OpenChallenge (https://www.openchallenge.org/ )
V. WEB REFERENCE:
1. http://www.personal.kent.edu/~rmuhamma/Algorithms/algorithm.html
2. http://openclassroom.stanford.edu/MainFolder/CoursePage.php?course=IntroToAlgorithms
3. http://www.facweb.iitkgp.ernet.in/~sourav/daa.html
124