Design & Analysis of Algorithms (DAA) Unit - II
Design & Analysis of Algorithms (DAA) Unit - II
Greedy Programming: General Method, Knapsack problem, Job Sequencing with Dead Lines,
Minimum-cost Spanning Tree - Prim's and Kruskal's algorithms, Single-Source Shortest Paths-
Dijkstra's Algorithm.
Basic Traversal & Search Techniques: Techniques for Binary Trees, Techniques for Graphs,
Connected Components and Spanning Trees, Bi-Connected Components and DFS.
Greedy Programming
General Method:
Most of the problems in Greedy method have n inputs and require us to obtain a subset that
satisfy some constraints. Any subset that satisfies these constraints is called a feasible solution.
A feasible solution that either maximizes or minimizes a given objective function is called an
optimal solution. If the problem requires that only a subset of n inputs need to be selected
for its solution, then that type of problem can be solved by using greedy method “subset
paradigm”. If the problem requires that all of n inputs need to be selected for its solution but the
order of input is important, then that type of problems can be solved by using Greedy technique
“ordering paradigm”.
Characteristics of Greedy technique:
• Solution is built in stages at each stage. One of the input will be selected and will test for
feasibility, If that selected input is feasible then it will be included in the solution.
• The solution returned by the Greedy algorithms may not be an optimal solution.
• The decision that are made in the earlier stages are fixed and can’t be changed in next
stage.
Control abstraction of subset paradigm for Greedy method:
Algorithm Greedy(a, n)
{
//a[1:n] contains n inputs
solution:=ɸ
for i:=1 to n do
{
x:=select(a);
If (Feasible (solution, x)) then
solution:=Union(solution,x);
}
return solution;
}
Knapsack Problem:
Given n objects and a knapsack or bag, object ‘i’ has a weight wi and profit pi. The knapsack has
a capacity ‘m’. If a fraction x is 0 ≤ xi ≤ 1 of object ‘i’ is placed in knapsack, then profit pi xi is
obtained.
The objective is to obtain a filling of the knapsack that maximizes the total profit earned.
i.e. Maximize ∑1≤𝑖≤𝑛 𝑝𝑖𝑥𝑖→ (1)
Subject to ∑1≤𝑖≤𝑛 𝑤𝑖𝑥𝑖 ≤ 𝑚→ (2), where 0 ≤ x i≤ 1, 1 ≤ i≤ n → (3)
A feasible solution is any set (x1, x2… xn) satisfying the above constraints (2) and (3). An
optimal solution is a feasible solution that maximizes (1)
Problem:
1. Consider the following instance of the knapsack problem n=3, m=20, (p1, p2, p3)=(25, 24,
15) and (w1, w2, w3)=(18,15,10).
Sol: Some possible Solution sets:
1. Select according to ascending order of weights.
(0, 10/15, 1) 25*0+24*(2/3)+15*1=31
2. Select according to descending order of profit.
(1, 2/15, 0) 25*1+24*(2/15)+15*0=28.2
3. Randomly selected objects.
(1/2, 1/3, 6/10) 25*(1/2)+(1/3)*24+15*(6/10)=29.5
4. Select objects in decreasing order of profit/weight ratio.
(0, 1, 5/10) 25*0+24*1+15*(1/2)=31.5
2. Consider the following instance of the knapsack problem n=7,m=15, (p1,p2…p7) = (10, 5,
15, 7, 6, 18, 3) and (w1, w2…w7)=(2,3,5,7,1,4,1).
Sol: arrange the object in decreasing order of profit/weight ratio.
𝑝/𝑤 = (10/2, 5/3,15/5,7/7,6/1,18/4,3/1)=(5, 1.67, 3, 1, 6, 4.5, 3)
Solution set x[ ]= (1, 2/3, 1, 0, 1, 1, 1)
Total Profit obtained = 1*10+(2/3)*5+15*1+7*0+6*1+18*1+3*1
= 10+(10/3)+15+0+6+18+3
= 55.3
Algorithm:
Algorithm knapsack(m, n)
{
//p[1:n] are profits and w[1:n] are weights of n objects
//the objects are given in decreasing order of pro
//x[1:n] is the solution set
for i:= 1 to n do x[i]:= 0.0;
U:=m;
for i:=1 to n do
{
if (w[i]>U) then break;
x[i]:=1.0;
U:= U-w[i];
}
if (i≤n) then x[i]:=U/w[i];
}
Implementation:
#include<stdio.h>
int main(){
int n, m, i, j, t;
int p[100],w[100];
printf("Enter size: ");
scanf("%d",&n);
printf("Enter maximum capacity: ");
scanf("%d",&m);
printf("Enter the profits: ");
for(i=0;i<n;i++)
scanf("%d",&p[i]);
printf("Enter the weights: ");
for(i=0;i<n;i++)
scanf("%d",&w[i]);
for(i=0;i<n;i++) {
for(j=0;j<n-i-1;j++) {
float t1 = (float) p[j]/w[j];
float t2 = (float) p[j+1]/w[j+1];
if(t1<t2) {
t=w[j];
w[j]=w[j+1];
w[j+1]=t;
t=p[j];
p[j]=p[j+1];
p[j+1]=t;
}
}
}
float result[100];
for(i=0;i<n;i++)
result[i]=0;
float profit = 0;
for (i = 0; i < n; i++) {
if (w[i] > m)
break;
result[i] = 1;
m = m - w[i];
profit += p[i];
}
if (i <= n) {
result[i] = (float) m / w[i];
2. Find the optimal sequence of jobs to be executed on a machine from the following instance of
job sequencing with deadlines n=5, (p1, p2, p3, p4, p5)=(20, 15, 10, 5, 1) and (d1, d2, d3, d4,
d5)=(2, 2, 1, 3, 3).
Sol: Method of solving JSD is as follows
3. Find the optimal sequence of jobs to be executed on a machine from the following instance of
job sequencing with deadlines n=4, (p1, p2…p7)=(3,5,20,18,1,6,30) and (d1, d2,... d7)=(1, 3, 4,
3, 2, 1, 2).
Sol: Arrange the objects in non-increasing order of profits
(p7, p3, p4, p6, p2, p1, p5)= (30, 20, 18, 6, 5, 3, 1)
(d7, d3, d4, d6, d2, d1, d5)= (2, 4, 3, 1, 3, 1, 2)
J Assigned slots Job action profit
consideration
____ 7 Assign to [1, 2] 0
Algorithm:
Algorithm JSD(d, j, n)
{
//deadlines d[i] ≥1; 1≤i≤n
//profits are arranged in non-increasing order
//p[1] ≥ p[2]….. ≥p[n]
//J[ ] is the array of jobs selected
d[0]:=J[0]:=0;
J[1]:=1;
k:=1; //k is number of jobs
for i:=2 to n do //i is job number
{
r:=k;
//look at position for job i and insert
//if feasible
while (d[J[r]]>d[i] and d[J[r]]≠r) do
r:=r-1;
if(d[J[r]) ≤d[i] and d[i]> r) then
{
for q:=k to r+1 step-1 do
J[q+1]:=J[q];
J[r+1]:=i;
k:=k+1;
}
}
return k;
}
Implementation:
#include <stdio.h>
int maxi(int a[],int n){
int i,m=a[0];
for(i=0;i<n;i++)
if(a[i]>m)
m=a[i];
return m;
}
int main()
{
int i,j,n;
printf("Enter the value of n: ");
scanf("%d",&n);
int profits[n],dead[n];
printf("Enter the profits: ");
for(i=0;i<n;i++)
scanf("%d",&profits[i]);
printf("Enter the dead lines: ");
for(i=0;i<n;i++)
scanf("%d",&dead[i]);
for(i=0;i<n;i++){
for(j=i+1;j<n;j++){
if(profits[i]<profits[j]){
int temp=profits[i];
profits[i]=profits[j];
profits[j]=temp;
temp=dead[i];
dead[i]=dead[j];
dead[j]=temp;
}
}
}
int max=maxi(dead,n);
int profit=0,w;
int visited[max];
for(i=0;i<max;i++)
visited[i]=0;
for(i=0;i<n;i++){
w=dead[i];
for(j=w-1;j>=0;j--){
if(visited[j]==0){
visited[j]=1;
profit+=profits[i];
break;
}
}
}
printf("Total Profit = %d",profit);
return 0;
}
The cost of spanning tree is the sum of costs (or) weights of the edges in tree. The minimum cost
spanning tree(MCSP) is the spanning tree whose sum of costs (or) weights of the edges in tree is
minimum for the given undirected connected graph.
There are two basic algorithms for finding minimum-cost spanning trees, and both are greedy
algorithms
• Prim‟s Algorithm
• Kruskal‟s Algorithm
Prim’s Algorithm:
i) Select an edge with minimum cost and include in to the spanning tree.
ii) Among all the edges which are adjacent with the selected edge, select the one with minimum
cost.
iii) Repeat step 2 until „n‟ vertices and (n-1) edges are been included. And the sub graph
obtained does not contain any cycles.
Example:
Algorithm:
Algorithm Prim (E, cost, n, t)
{
Let (k, l) be an edge of minimum cost in E;
mincost := cost [k, l];
t [1, 1] := k; t [1, 2] := l;
for i :=1 to n do // Initialize near
if (cost [i, l] < cost [i, k]) then near [i] := l;
else near [i] := k;
near [k] :=near [l] := 0;
for i:=2 to n - 1 do // Find n - 2 additional edges for t.
{
Let j be an index such that near [j] <> 0 and cost [j, near [j]] is minimum;
t [i, 1] := j; t [i, 2] := near [j];
mincost := mincost + cost [j, near [j]];
near [j] := 0
for k:= 1 to n do // Update near[].
if ((near[k] <> 0) and (cost [k, near [k]] > cost [k, j]))
then near [k] := j;
}
return mincost;
}
Implementation:
#include<stdio.h>
#define INF 9999999
int main() {
int no_edge,V,cost=0,i,j;
int selected[V];
printf("Enter number of edges: ");
scanf("%d",&V);
int G[V][V];
printf("Enter the adjacency matrix:\n");
for(i=0;i<V;i++)
for(j=0;j<V;j++)
scanf("%d",&G[i][j]);
for(i=0;i<V;i++)
selected[i]=0;
no_edge = 0;
selected[0] = 1;
int x;
int y;
printf("Edge : Weight\n");
while (no_edge < V - 1) {
int min = INF;
x = 0;
y = 0;
for (int i = 0; i < V; i++) {
if (selected[i]) {
for (int j = 0; j < V; j++) {
if (!selected[j] && G[i][j]){
if (min > G[i][j]) {
min = G[i][j];
x = i;
y = j;
}
}
}
}
}
printf("%d - %d : %d\n", x, y, G[x][y]);
cost+=G[x][y];
selected[y] = 1;
no_edge++;
}
printf("Minimum Cost = %d",cost);
return 0;
}
Kruskal’s Algorithm:
The algorithm also uses greedy method to get the minimum spanning tree.
Initially all the edges are arranged in the non-decreasing order, based on the cost of the edges. At
each stage an edge with the minimum cost is selected following the constraint that selection of
this edge does not result in a cycle(or)loop.
Procedure:
Step 1: Initially arrange the edges of a graph in the non-decreasing order of their cost .
Step 2: Select the minimum cost edge and it is going to be first edge in the spanning tree.
Step 3: Now select the minimum cost edge from the remaining edges following the constraint
that the selection of that edge does not result in cycle or loop
Step 4: If more than one edge has the same minimum cost then arbitrarily select any one of them
Step 5: repeat step3 until there are n-1 edges in the spanning tree.
Example:
Algorithm:
Algorithm krushkal(E,cost,n,t)
{
//E is the set of edges in G of 'n' vertices
//cost [ , ] is cost adjacency matrix
//t is set of edges in the minimum cost
//spanning tree.
Construct a heap out of edge costs using heapify;
for i:=1 to n do parent[i]:= -1;
i:=0;
mincost:=0;
while (i<n-1 and (heap is not empty))
{
Delete a mininum cost edge (u,v) from the heap and
heapify using adjust;
j:=find(u);
k:=find(v);
if (j≠k) then
{
i:=i+1;
t[i,1]:=u;
t[i,2]:=v;
mincost:=mincost+cost[u,v];
union(j,k);
}
}
if (i<n-1) then
Write ("No spanning tree");
else
return mincost;
}
}
printf("Edge : Cost\n");
while(ne<n){
for(i=0,min=999;i<n;i++){
for(j=0;j<n;j++){
if(cost[i][j]<min){
min=cost[i][j];
a=u=i;
b=v=j;
}
}
}
u=find(u);
v=find(v);
if(uni(u,v)){
printf("%d - %d : %d\n", a, b, min);
mincost +=min;
}
ne++;
cost[a][b]=cost[b][a]=999;
}
printf("Minimum cost = %d",mincost);
return 0;
}
Performance:
To build min-heap with edges : O(|E|)
Iterate through edges for cycle detection and deleteMin to get next edge : O(|E| log |E|)
We can do Union in constant time.
We can get Find with worst case O(log (|V|)
Path length
1-2 10
1-5-4-3 26
1-5-4 20
1-5 5
Procedure:
• Let 'v' be the source vertex and cost[ ] be the 2-dimentional array of edge cost,
distance[i] is the distance of each vertex i from source vertex 'v'.
• Select the vertex which has the minimum distance value among unvisited vertices and
declare it as visited. Let that vertex be 'u'.
• Update the distance[i] values of adjacent unvisited vertices of vertex u by using the
following condition:
• Let 'w' be an adjacent vertex of 'u',
• if (distance[w] > distance[u]+cost[u,w]) distance [w]= distance[u]+cost[u,w])
• Repeat steps 2,3 until all the vertices are declared as visited.
Problems:
1. Find the shortest paths from source vertex 'A' to each vertex in the graph
Sol:
initial − A 0 1 2 ∞ ∞ ∞ 3
1 A B 0 1 2 5 ∞ ∞ 3
2 {A,B} C 0 1 2 5 5 3 3
3 {A,B,C} F 0 1 2 5 5 3 3
4 {A,B,C,F} G 0 1 2 5 5 3 3
5 {A,B,C,F,G} E 0 1 2 5 5 3 3
6 {A,B,C,E,F,G} D 0 1 2 5 5 3 3
Initial − E ∞ ∞ ∞ 15 0 2 ∞ ∞
1 {E} F ∞ ∞ ∞ 12 0 2 11 16
2 {E,F} G ∞ ∞ ∞ 12 0 2 11 16
3 {E,F,G} D ∞ ∞ 24 12 0 2 11 16
4 {D,E,F,G} H 33 ∞ 24 12 0 2 11 16
5 { D,E,F,G,H} C 33 32 24 12 0 2 11 16
6 {C, D,E,F,G,H } B 33 32 24 12 0 2 11 16
7 {B,C, D,E,F,G,H} A 33 32 24 12 0 2 11 16
Algorithm:
Algorithm shortestpath (v,cost,dist,n)
{
//dist[j],1≤j≤n is set to the length of
//shortest path from source vertex v to vertex j
//in a digraph G with 'n' vertices. G is represented
//by cost adjacency matrix C[1:n,1:n] for i:=1 to n do
{
S[i]:=false; dist[i]:=cost[v,i];
}
S[v]:=true;
dist[v]:=0.0;
for num:= 2 to n-1 do
{
Choose u from among the vertices not in S, such that dist[u] is minimum;
S[u]:=true;
for (each w adjacent to u with S[w]=false) do
{
if(dist[w]>dist[u]+cost[u,w]) then dist[w]:=dist[u]+cost[u,w];
}
}
}
Implementation:
#include<stdio.h>
#include<string.h>
#define INF 9999999
int minCost(int cost[],int visited[],int v){
int min=INF;
int mi=0;
for(int i=0;i<v;i++){
if(cost[i]<min && !visited[i]){
min=cost[i];
mi=i;
}
}
return mi;
}
int main() {
int no_edge,V,i,j;
printf("Enter number of edges: ");
scanf("%d",&V);
int visited[V];
memset(visited,0,V*sizeof(int));
int G[V][V];
int cost[V];
memset(cost,INF,V*sizeof(int));
printf("Enter the adjacency matrix:\n");
for(i=0;i<V;i++)
for(j=0;j<V;j++)
scanf("%d",&G[i][j]);
no_edge = 0;
cost[0] = 0;
while (no_edge < V - 1){
int u=minCost(cost,visited,V);
visited[u]=1;
for (i = 0; i < V; i++)
if (G[u][i] && cost[u]+G[u][i]<cost[i] && !visited[i])
cost[i]=cost[u]+G[u][i];
no_edge++;
}
printf("Vertex Cost\n");
for(i=0;i<V;i++)
printf("%d %d\n",i+1,cost[i]);
return 0;
}
Example:
In-order Traversal: F D H G I B E A C
• Pre-order Traversal: A B D F G H I E C
• Post-order Traversal: F H I G D E B C A
• The total time taken to the above
three algorithms are 𝑂(𝑛)
Tree Construction
• Inorder sequence: D B E A F C
• Preorder sequence: A B D E C F
• Inorder sequence: D B E A F C
• Postorder sequence: D E B F C A
Note:
• In-order and post-order sequences of a binary tree uniquely define the binary tree.
• In-order and pre-order sequences of a binary tree uniquely define the binary tree.
• Post-order and pre-order sequences of a binary tree do not uniquely define the binary
tree.
Example:
8
6
1 7 5
1
2
4 6 2 7 9
3 3 8 1
4 1 9 5
Algorithm for finding Articulation Points
Algorithm Art(u, v)
//It is assumed that the global array dfn is initialized to zero
//global variable num is initialized to 1. n is the number of vertices in G.
{
dfn[u] := num; L[u] := num; num := num + 1;
for each vertex w adjacent from u do
{
if (dfn[w] = 0) then
{
Art(w,u); // w is unvisited.
L[u] := min(L[u], L[w]);
}
else if (w != v) then L[u] := min(L[u],dfn[w]);
}
}
Algorithm for finding bi-connected components:
Algorithm BiComp (u, v)
{
dfn [u] := num; L[u] := num; num := num + 1;
for each vertex w adjacent from u do
{
if ((v != w) and (dfn [w] < dfn [u])) then
add (u, w) to the top of a stack s;
if (dfn [w] = 0) then
{
BiComp (w, u); // w is unvisited.
L [u] := min (L [u], L [w]);
if (L [w] >= dfn [u]) then
{
write (“New bicomponent”);
repeat {
Delete an edge from the top of stack s;
Let this edge be (x, y);
Write (x, y);
} until (((x, y) = (u, w)) or ((x, y) = (w, u)));
}
}
else if (w != v) then L [u] : = min (L [u], dfn [w]);
}
}
***