Unit - 4 Daa
Unit - 4 Daa
Dynamic Programming:
Dynamic programming is a technique that breaks the problems into sub-problems, and
saves the result for future purposes so that we do not need to compute the result again.
The subproblems are optimized to optimize the overall solution is known as optimal
substructure property. The main use of dynamic programming is to solve optimization
problems. Here, optimization problems mean that when we are trying to find out the
minimum or the maximum solution of a problem. The dynamic programming
guarantees to find the optimal solution of a problem if the solution exists.
The definition of dynamic programming says that it is a technique for solving a complex
problem by first breaking into a collection of simpler subproblems, solving each
subproblem just once, and then storing their solutions to avoid repetitive computations.
One of the most basic, classic examples of this process is the Fibonacci Sequence.
Applications:
Rod Cutting Problem:
The Rod Cutting Problem is a classic example of dynamic programming. Given a rod
of length n and a table of prices that contains the prices of all pieces of length smaller
than or equal to n, the goal is to determine the maximum revenue obtainable by cutting
the rod and selling the pieces.
Problem Definition:
• Input:
o n: The length of the rod.
o price[]: An array of prices where price[i] denotes the price of a rod of length i+1.
• Output: The maximum revenue obtainable by cutting up the rod and selling the
pieces.
Approach:
1. Brute Force: Consider all possible ways to cut the rod and calculate the revenue for
each cut. This leads to an exponential time complexity as it involves solving the
same subproblems multiple times.
2. Dynamic Programming: Break down the problem into smaller subproblems, store
the solutions to these subproblems, and build up the final solution efficiently.
Optimal Substructure:
If the best way to cut a rod of length n involves cutting off a piece of length i, then the
problem reduces to finding the best way to cut a rod of length n-i.
• Finally, dp[n] will contain the maximum revenue for a rod of length n.
Example:
Given a rod of length 4 and price array price[] = {1, 5, 8, 9}:
• Possible cuts and corresponding revenues:
o Cut the rod into lengths (1, 1, 1, 1): Revenue = 1+1+1+1 = 4
o Cut the rod into lengths (2, 2): Revenue = 5+5 = 10
o Cut the rod into lengths (3, 1): Revenue = 8+1 = 9
o Cut the rod into lengths (4): Revenue = 9
The maximum revenue is 10, achieved by cutting the rod into two pieces of length 2.
Floyd-Warshall Algorithm:
The Floyd Warshall Algorithm is an all-pair shortest path algorithm
unlike Dijkstra and Bellman Ford which are single source shortest path algorithms.
This algorithm works for both the directed and undirected weighted graphs. But it
does not work for the graphs with negative cycles (where the sum of the edges in a cycle
is negative). It follows Dynamic Programming approach to check every possible path
going via every possible node in order to calculate shortest distance between every pair
of nodes.
Idea Behind Floyd Warshall Algorithm:
Suppose we have a graph G[][] with V vertices from 1 to N. Now we have to evaluate
a shortestPathMatrix[][] where shortestPathMatrix[i][j] represents the shortest path
between vertices i and j.
Obviously, the shortest path between i to j will have some k number of intermediate
nodes. The idea behind floyd warshall algorithm is to treat each and every vertex
from 1 to N as an intermediate node one by one.
The following figure shows the above optimal substructure property in floyd warshall
algorithm:
Step 1: Initialize the Distance[][] matrix using the input graph such that Distance[i][j]=
weight of edge from i to j, also Distance[i][j] = Infinity if there is no edge from i to j.
Step 2: Treat node A as an intermediate node and calculate the Distance[][] for every
{i,j} node pair using the formula:
= Distance[i][j] = minimum (Distance[i][j], (Distance from i to A) + (Distance
from A to j ))
= Distance[i][j] = minimum (Distance[i][j], Distance[i][A] + Distance[A][j])
Step 3: Treat node B as an intermediate node and calculate the Distance[][] for every
{i,j} node pair using the formula:
= Distance[i][j] = minimum (Distance[i][j], (Distance from i to B) + (Distance
from B to j ))
= Distance[i][j] = minimum (Distance[i][j], Distance[i][B] + Distance[B][j])
Step 4: Treat node C as an intermediate node and calculate the Distance[][] for every
{i,j} node pair using the formula:
= Distance[i][j] = minimum (Distance[i][j], (Distance from i to C) + (Distance
from C to j ))
= Distance[i][j] = minimum (Distance[i][j], Distance[i][C] + Distance[C][j])
Step 5: Treat node D as an intermediate node and calculate the Distance[][] for every
{i,j} node pair using the formula:
= Distance[i][j] = minimum (Distance[i][j], (Distance from i to D) + (Distance
from D to j ))
= Distance[i][j] = minimum (Distance[i][j], Distance[i][D] + Distance[D][j])
Step 6: Treat node E as an intermediate node and calculate the Distance[][] for every
{i,j} node pair using the formula:
= Distance[i][j] = minimum (Distance[i][j], (Distance from i to E) + (Distance
from E to j ))
= Distance[i][j] = minimum (Distance[i][j], Distance[i][E] + Distance[E][j])
Step 7: Since all the nodes have been treated as an intermediate node, we can now return
the updated Distance[][] matrix as our answer matrix.
• Once the parenthesization is done, the optimal substructure must be devised as the
first step of dynamic programming approach so the final product achieved is
optimal. In matrix chain multiplication, the optimal substructure is found by
dividing the sequence of matrices A[i….j] into two parts A[i,k] and A[k+1,j]. It must
be ensured that the parts are divided in such a way that optimal solution is achieved.
• Using the following formula, find the lowest cost parenthesization of the sequence
of matrices by constructing cost tables and corresponding k values table.
• Once the lowest cost is found, print the corresponding parenthesization as the output.
Travelling Salesman Problem:
Given a set of cities and the distance between every pair of cities, the problem is to find
the shortest possible route that visits every city exactly once and returns to the starting
point.
Note the difference between Hamiltonian Cycle and TSP. The Hamiltonian cycle
problem is to find if there exists a tour that visits every city exactly once. Here we know
that Hamiltonian Tour exists (because the graph is complete) and in fact, many such
tours exist, the problem is to find a minimum weight Hamiltonian Cycle.
For example, consider the graph shown in the above figure. A TSP tour in the graph is
1-2-4-3-1. The cost of the tour is 10+25+30+15 which is 80. The problem is a famous
NP-hard problem. There is no polynomial-time know solution for this problem. The
following are different solutions for the traveling salesman problem.
Naive Solution:
1) Consider city 1 as the starting and ending point.
2) Generate all (n-1)! Permutations of cities.
3) Calculate the cost of every permutation and keep track of the minimum cost
permutation.
4) Return the permutation with minimum cost.
Dynamic Programming Approach:
Let us consider a graph G = (V,E), where V is a set of cities and E is a set of weighted
edges. An edge e(u, v) represents that vertices u and v are connected. Distance between
vertex u and v is d(u, v), which should be non-negative.
Suppose we have started at city 1 and after visiting some cities now we are in city j.
Hence, this is a partial tour. We certainly need to know j, since this will determine which
cities are most convenient to visit next. We also need to know all the cities visited so
far, so that we don't repeat any of them. Hence, this is an appropriate sub-problem.
For a subset of cities S ϵϵ {1,2,3,...,n} that includes 1, and j ϵϵ S, let C(S, j) be the
length of the shortest path visiting each node in S exactly once, starting at 1 and ending
at j.
When |S|> 1 , we define 𝑪C(S,1)= ∝∝ since the path cannot start and end at 1.
Now, let express C(S, j) in terms of smaller sub-problems. We need to start at 1 and end
at j. We should select the next city in such a way that
Algorithm: Traveling-Salesman-Problem
C ({1}, 1) = 0
for s = 2 to n do
for all subsets S є {1, 2, 3, … , n} of size s and containing 1
C (S, 1) = ∞
for all j є S and j ≠ 1
C (S, j) = min {C (S – {j}, i) + d(i, j) for i є S and i ≠ j}
Return minj C ({1, 2, 3, …, n}, j) + d(j, i)
Analysis:
There are at the most 2n.n sub-problems and each one takes linear time to solve.
Therefore, the total running time is O(2n.n2).
Example:
In the following example, we will illustrate the steps to solve the travelling salesman
problem.
From the above graph, the following table is prepared.
1 2 3 4
1 0 10 15 20
2 5 0 9 10
3 6 13 0 12
4 8 8 9 0
Start from cost {1, {2, 3, 4}, 1}, we get the minimum value for d [1, 2]. When s = 3,
select the path from 1 to 2 (cost is 10) then go backwards. When s = 2, we get the
minimum value for d [4, 2]. Select the path from 2 to 4 (cost is 10) then go backwards.
When s = 1, we get the minimum value for d [4, 2] but 2 and 4 is already selected.
Therefore, we select d [4, 3] (two possible values are 15 for d [2, 3] and d [4, 3], but our
last node of the path is 4). Select path 4 to 3 (cost is 9), then go to s = ϕ step. We get the
minimum value for d [3, 1] (cost is 6).
The following steps are followed for finding the longest common subsequence.
1. Create a table of dimension n+1*m+1 where n and m are the lengths
of X and Y respectively. The first row and the first column are filled with zeros.
6. The value in the last row and the last column is the length of the longest common
subsequence.
7. In order to find the longest common subsequence, start from the last element and
follow the direction of the arrow. The elements corresponding to () symbol form the
longest common subsequence.
Thus, the longest common subsequence is CA.
Backtracking Algorithm:
A backtracking algorithm is a problem-solving algorithm that uses a brute force
approach for finding the desired output.
The term backtracking suggests that if the current solution is not suitable, then backtrack
and try other solutions. Thus, recursion is used in this approach.
This approach is used to solve problems that have multiple solutions.
8-Queen Problem:
Problem Statement: Given an 8*8 chess board, you must place 8 queens on the board
so that no two queens attack each other. Print all possible matrices satisfying the
conditions with positions with queens marked with '1' and empty spaces with '0'. You
must solve the 8 queens problem using backtracking.
Note: A queen can move vertically, horizontally and diagonally in any number of steps.
Algorithm:
• Create a function backtrack that simply places the queens on corresponding rows
and columns and marks them visited.
• The working of backtrack is as follows:
o If the current row is equal to 8, then a solution has been found. Therefore, add
this to the answer.
o Traverse through the columns of the current row. At each column, try to place
the queen in (row, col):
▪ Calculate the diagonal and anti-diagonal which the current square belongs
to. If it is unvisited, place the queen in the (row, col).
▪ Skip this column, if the queen cannot be visited.
o If the queen has been placed successfully, call the backtrack function of row +
1.
o Since, all paths have now been explored, clear the values of the queens placed
so far and the visiting arrays, so that next distinct solution can be found.
Example:
One possible solution to the 8 queens problem using backtracking is shown below. In
the first row, the queen is at E8 square, so we have to make sure no queen is in column
E and row 8 and also along its diagonals. Similarly, for the second row, the queen is on
the B7 square, thus, we have to secure its horizontal, vertical, and diagonal squares. The
same pattern is followed for the rest of the queens.
Knapsack Problem:
We discussed the fractional knapsack problem using the greedy approach earlier. It is
shown that Greedy approach gives an optimal solution for Fractional Knapsack.
However, this will cover 0-1 Knapsack problem using dynamic programming
approach and its analysis.
Unlike in fractional knapsack, the items are always stored fully without using the
fractional part of them. Its either the item is added to the knapsack or not. That is why,
this method is known as the 0-1 Knapsack problem.
Hence, in case of 0-1 Knapsack, the value of xi can be either 0 or 1, where other
constraints remain the same. Means that the items are either completely or no items are
filled in a knapsack.
0-1 Knapsack cannot be solved by Greedy approach. Greedy approach does not ensure
an optimal solution in this method. In many instances, Greedy approach may give an
optimal solution.
0-1 Knapsack Algorithm:
Problem Statement − A thief is robbing a store and can carry a maximal weight
of W into his knapsack. There are n items and weight of ith item is wi and the profit of
selecting this item is pi. What items should the thief take?
Let i be the highest-numbered item in an optimal solution S for W dollars. Then S’ = S
− {i} is an optimal solution for W – wi dollars and the value to the solution S is Vi plus
the value of the sub-problem.
We can express this fact in the following formula: define c[i, w] to be the solution for
items 1,2, … , i and the maximum weight w.
The algorithm takes the following inputs
• The maximum weight W
• The number of items n
• The two sequences v = <v1, v2, …, vn> and w = <w1, w2, …, wn>
The set of items to take can be deduced from the table, starting at c[n, w] and tracing
backwards where the optimal values came from.
If c[i, w] = c[i-1, w], then item i is not part of the solution, and we continue tracing
with c[i-1, w]. Otherwise, item i is part of the solution, and we continue tracing with c
[i-1, w-W].
Example:
Let us consider that the capacity of the knapsack is W = 8 and the items are as shown
in the following table.
Item A B C D
Profit 2 4 7 10
Weight 1 3 5 7
Solution:
Using the greedy approach of 0-1 knapsack, the weight that’s stored in the knapsack
would be A+B = 4 with the maximum profit 2 + 4 = 6. But, that solution would not be
the optimal solution.
Therefore, dynamic programming must be adopted to solve 0-1 knapsack problems.
Step 1:
Construct an adjacency table with maximum weight of knapsack as rows and items with
respective weights and profits as columns.
Values to be stored in the table are cumulative profits of the items whose weights do not
exceed the maximum weight of the knapsack (designated values of each row)
So, we add zeroes to the 0th row and 0th column because if the weight of item is 0, then
it weighs nothing; if the maximum weight of knapsack is 0, then no item can be added
into the knapsack.
The remaining values are filled with the maximum profit achievable with respect to the
items and weight per column that can be stored in the knapsack.
The formula to store the profit values is −
By computing all the values using the formula, the table obtained would be –
To find the items to be added in the knapsack, recognize the maximum profit from the
table and identify the items that make up the profit, in this example, its {1, 7}.
Analysis:
This algorithm takes Ɵ(n.w) times as table c has (n+1).(w+1) entries, where each entry
requires Ɵ(1) time to compute.