You are on page 1of 51

UNIVERSITY INSTITUTE OF ENGINEERING AND TECHNOLOGY 

    
PANJAB UNIVERSITY, SECTOR 25, CHANDIGARH

Analysis and Design of Algorithms (PRACTICAL) (CS451)

LAB REPORT

CSE DEPARTMENT 
BATCH : 2020-24

SUBMITTED BY:                                  SUPERVISED BY:  


              Angel Sharma (UE203015)                                          Dr. Mukesh Kumar

              CSE SECTION-1, Sem-4 

Group 1                  
-- then we start searching the required
Task:- Linear Search element in the array
Analysis ● If the element is found then we
increment the successful
Introduction – elements found otherwise we
The linear search is a popular algorithm in increment the number of
computer science to find the index of a unsuccessful elements.
particular user provided key in the given list ● Meanwhile in each case in
of numbers/elements. A linear search is a which the element is found we
quite slow algorithm as it has to compare keep storing that index so that
every element in the list. It has a worst-case we can calculate the average
time complexity of O(n) when it has to index where the element is
search the entire array for finding that found in this linear search.
particular element. An advantage of linear --for each size of the array different
search is that it does not require the list to elements are searched in the array 100
be sorted. times and then the average time is taken
out for each array size.

Algorithm –
A simple algorithm of linear search is shown Code:-
below:- #include <iostream>
#include <chrono>
LinearSearch(array, key){ using namespace std::chrono;
using namespace std;
For i from 1 to size of array int main()
{
If array[i] == key     int time, s = 0, u = 0, n, t;
    int p[15];
return i     for (int x = 0; x < 15000; x += 1000)

    {
        int a[1000 + x];
Procedure:-  
 
 
 
 
 
 
 
for (int i = 0; i < 1000 + x; i++)
{
            a[i] = rand() % (1001 + x);
-- Create an array of variable sizes and store
random elements in it.             /* code */
        }
-- then randomly generate a number which         t = 0,time=0,s=0,u=0;
is to be searched in the array using linear         for (int i = 0; i < 100; i++)
        {
search.             n = rand() % (1001 + x);
            int k = 0;
            auto start =
steady_clock::now();
            for (int j = 0; j < 1000 + x;
j++)
            {
                if (n == a[j])
                {

                    s++;
                    t = t + j;
                    k = 1;
                    break;
                    /* code */
                }

                /* code */
            }
            if (k == 0)
            {
                u++;
               
                /* code */
            }
            auto end = steady_clock::now();
            auto duration = Graphs:-
duration_cast<nanoseconds>(end - start);
           
time=time+duration.count();
1. Number of elements vs
            /* code */ Time:
        }
cout<<t/100<<" "<<s<<" "<<u<<"
"<<time/100<<endl;
        /* code */
    }
}

Output:-

2. Number of elements vs
Average Index:
This experiment gave us an insight on the
time complexity of linear search. From this
experiment, we learned about the linear
relationship between the time taken and
the size of elements for linear search
algorithm. We also learned how the
background processes interfere in the
analysis of the algorithm and the various
other factors that leads to inconsistencies.

Conclusion –
3. Number of elements
From this experiment we concluded that
vs Number of the best case time complexity of linear
successful keys found: search is O(1) and the worst case time
complexity is O(n).

Result:-
From the graph we can conclude that as the
size of the array increases the time taken to
search the element also increases almost
linearly though here the graph is not exactly
linear because the number of successful
cases vary in different sized arrays and thus
the cases in which no element is found
contribute to the worst case time taken.

Learnings –
return i
Task:- N-array Search
Analysis
Procedure:-
Introduction – ● First we randomly create
an array of size 1000 and
The nary search is a searching technique in
then insert random
computer science in which we divide the
elements in the array.
array into n parts and then compare one
● Then we sort the given
element from each part. If the element is
array for n-array search.
greater than a given value then we search
● loop for generating 50
to the left of it, if it is greater than the right
random numbers to be
part then we search to the right of it and if a
searched in the array is
match is found, return it. This technique is
created and then we call
based on divide and conquer. The binary
the n-array function
search is a very common example of nary
where the n value is
search. An important condition of nary
input by the user and its
search is that the array must be sorted.
value in the
n_array_search function
varies from 2 to n.
Algorithm –
● Now as the function is
A simple algorithm of nary search is shown called we paas the
below:- arguments (a,l,r,p,i)
where these stand for
N_ary_Search(array, key, N){
the array, left most index
low =0, high = size(array) – 1 of array,rightmost
while low <= high index,element to be
searched(randomly
for i 1..n generated value) and the
if array[low + i*(high – low + 1)/n] < value of n(that varies
key from 2 to n) respectively.
● now once the function is
low = mid+1 called then we first store
else if array[low + i*(high – low + the mid values un a array
1)/n] > key as per the value of n
where the array is mid
high = mid-1
with size equal to n+1 to
else store values from l to r.
● then the function checks         for (int i = 0; i < n + 1; i++)
        {
whether the element is             mid[i] = l + i * ((r - l) / n);
either present at either             if (p == a[mid[i]])
            {
of the mid positions or
                return mid[i];
not. If yes then the                 /* code */
function returns the             }
        }
value of that position in         for (int i = 0; i < n; i++)
the array.         {
            if (p > mid[i] && p < mid[i +
● Now as the loop of mid
1])
finishes and the element             {
is not found at the mid                 return n_ary_search(a,
mid[i] + 1, mid[i + 1] - 1, p, n);
positions then the same                 /* code */
function of             }
n_array_search is called
            /* code */
again with         }
arguments(a,mid[i]+1,mi
        /* code */
d[i+1]-1,p,i) such that     }
now the element is
checked in this part of     return -1;
}
the array and this keeps int main()
on going till the element {
    int n;
is found.     int time = 0, s = 0, u = 0, t;
● If the element is found in     cin >> n;
the above mentioned     int a[1000];
    for (int i = 0; i < 1000; i++)
process then the function     {
returns the index where         a[i] = rand() % (1001);
        /* code */
the key is found else it
    }
returns -1.     sort(a, a + 1000);
    for (int i = 2; i <= n; i++)
    {
        s = 0, u = 0, time = 0, t = 0;
Code:-         /* code */

#include <bits/stdc++.h>         for (int j = 0; j < 50; j++)


#include <chrono>         {
using namespace std::chrono;             int p, q;
using namespace std;             p = rand() % (1001);
int n_ary_search(int a[], int l, int r, int             auto start =
p, int n) steady_clock::now();
{             q = n_ary_search(a, 0, 1000, p,
    if (r >= l) i);
    {             if (q != -1)
        int mid[n + 1];             {
                t = t + q;
                s++;
            }
            else
            {
                u++;
            }
            auto end = steady_clock::now();
            auto duration =
duration_cast<nanoseconds>(end - start);
            /* code */ time = time +
duration.count();
        }
        cout << time / 50 << " " << t / 50
<< " " << s << " " << u << endl; Learnings –
    }
} This experiment gave us an insight on the
how the time varies over different values of
N. From this experiment, we learned about
Output:- the relationship between the time taken
and the values of N. We also learned how
the background processes interfere in the
analysis of the algorithm and the various
other factors that leads to inconsistencies.

Conclusion –
From this experiment we concluded that
the best possible value of n depends on the
size of list and the type of elements in the
list. However, in general we can say that it
the optimal values are not very large

Graph:-
Average Time taken vs N-value:
● In case the initial array passed has
Task:- To find Min-Max length of one unit that is l=r then
using divide and conquer mi=ma=a[l] that is the only element
of the array.

Code:-
Introduction – #include<iostream>
#include<chrono>
The minmax technique is based on divide using namespace std::chrono;
and conquer algorithm. The idea of divide using namespace std;
and conquer is to divide a larger problem void min_max(int a[],int l,int r,int
&mi,int &ma){
into smaller parts until the problem become     if (l==r)
such small that it can be solved easily. In     {mi=ma=a[l];
    return ;
minmax we have to find the minimum and
        /* code */
maximum of a list of numbers. The     }
maximum is the largest element of the list     else if (l==r-1)
    {if (a[l]>a[r])
while the minimum element of the list.     {mi=min(mi,a[r]);
    ma=max(ma,a[l]);
        /* code */
    }
Procedure:-     else
    {
● First we create an array whose         mi=min(mi,a[l]);
minimum and maximum element is to         ma=max(ma,a[r]);
    }
be found. Elements are added    
randomly into the array.         /* code */
    }
● The we call the min_max function by     else
passing the arguments (a,l,r,mi,ma)     {
where a stands for the array, l is the         int mid=(l+r)/2;
        min_max(a,l,mid,mi,ma);
lowermost and r is the uppermost         min_max(a,mid+1,r,mi,ma);
index of the array and mi and ma are     }
    return;
the required elements to be found    
and ther are passes by reference. }
● Now we keep dividing the array into int main(){
for (int x = 0; x < 1500; x += 100)
small parts by recursively calling the     {int mi=INT16_MAX;
min_max function till l==r-1 that is  int ma=INT16_MAX;
 
the array size is 2.
        int a[100 + x];
● Now we compare the elements of the         for (int i = 0; i < x + 100; i++)
array and assign values accordingly to         {
            a[i] = rand() % (101 + x);
the mi and ma using min() and max()             /* code */
functions.         }
        auto start = steady_clock::now(); From the graph it is clear that the time
   min_max(a,0,100+x-1,mi,ma);
      taken by both, the minimum function and
        auto end = steady_clock::now(); the maximum function, increases as the size
        auto duration =
of list increases. The linear relationship
duration_cast<nanoseconds>(end - start);
        cout << duration.count() << " ," << between the two can be clearly seen in the
100 + x << endl; graph. Some inconsistency is present in the
}}
graph which could be caused by the
Output:- processes running in the background.

Learnings –
From this experiment we learnt about the
linear relationship between the time taken
and the size of list for finding minimum and
maximum element of the list. This means
that the greater the size of list, the more
time it will take to search for the element.
Here all the time complexities that is best,
worst and average are O(n).

Conclusion –
From this experiment, we concluded that
the no matter what the elements of the list
are the time complexity for finding
Graph:- minimum and maximum element of the list
cannot be less than O(n).

Task:-Merge Sort
Analysis – Analysis
Introduction – h++

The merge sort is a very famous sorting }


technique in computer science which is }
based on divide and conquer algorithm. In
this algorithm we divided the array into two
halves until only one element is left in the
Procedure:-
divided list. Then we start merging the two
lists in sorted order. ● First we create an array and
randomly insert elements in it and
then call the sort function passing the
Algorithm – arguments(a,l,r) where a is the array
and l and r denote begin and end of
Algorithm of merge sort –
the array.
MergeSort(array, low, high) ● Till l<r the array is kept dividing into 2
If low < high then parts recursively by the sort function.
● The the merge function is called
Mid = (low+high)/2 where we create two separate arrays
MergeSort(array, low, mid) b and c of sizes n1 and n2 respectively
which basically are the lengths of the
MergeSort(array, mid+1, high)
divided array that is n1 from l to mid
Merge(array, low, mid, high) and n2 from mid+1 to r. we store the
elements from array a into b and c as
}
per the n1 and n2 values.
● Now we take an integer k=l which
Merge(array, low, mid, high){ denotes the starting element of array
each time as per the sliced array.
i = low, h = 0, j = mid+1 ● Now we compare the elements of b
temp[high-low+1] and c and add the smaller ones in the
array a and increment the pointers to
while(i<=mid and j<=high){ these array as per condition. If either
if(array[i] < array[j]) then of the two conditions that are i<n1
and j<n2 are violated the loop stops.
temp[h] = array[i]
● Now the remaining elements of the
i++ array are added accordingly to the
else array a from the array whose
condition wasn’t violated.
temp[h] = array[j]
j++ Code:-
#include <iostream>     if (l < r)
#include <chrono>     {
using namespace std::chrono;         int mid = (l + r) / 2;
using namespace std;         sort(a, l, mid);
void merge(int a[], int l, int mid, int r)         sort(a, mid + 1, r);
{         merge(a, l, mid, r); /* code */
    int n1 = mid + 1 - l;     }
    int n2 = r - mid; }
    int b[n1], c[n2]; int main()
    for (int i = 0; i < n1; i++) {
    {     for (int x = 0; x < 1500; x += 100)
        b[i] = a[l + i];     {
        /* code */         int a[100 + x];
    }         for (int i = 0; i < x + 100; i++)
    for (int j = 0; j < n2; j++)         {
    {             a[i] = rand() % (101 + x);
        c[j] = a[mid + 1 + j];             /* code */
        /* code */         }
    }         auto start = steady_clock::now();
    int i = 0, j = 0, k = l;         sort(a, 0, 100 + x - 1);
    while (i < n1 && j < n2)         auto end = steady_clock::now();
    {         auto duration =
        if (b[i] > c[j]) duration_cast<nanoseconds>(end - start);
        {         cout << duration.count() << " ," <<
            a[k] = c[j]; 100 + x << endl;
            j++;         /* code */
            k++;     }
            /* code */ }
        }
        else
        {
            a[k] = b[i];
            i++; Output:-
            k++;
        }

        /* code */
    }
    while (i < n1)
    {
        a[k] = b[i];
        k++;
        i++;
        /* code */
    }
    while (j < n2)
    {
        a[k] = c[j];
        j++;
        k++;
    }
}
void sort(int a[], int l, int r)
{
Graph:-

Learnings –
This experiment gave us an insight on the
how the time complexity of the merge sort
varies as the size of the list increases. From
this experiment, we learnt about the
relationship between the time taken by the
merge sort algorithm and the size of list. We
also learned how the background processes
interfere in the analysis of the algorithm
and the various other factors that leads to
inconsistencies.

Conclusion –
From this experiment, we concluded that
the time complexity of merge sort remains
O(nlogn) regardless of the type of list. All,
the average, best and worst cases time
complexities of merge sort is O(nlogn).
array[j] = array[i]
Task:-Quick Sort Analysis
array[i] = temp
Introduction –
temp = array[r]
The quick sort is a famous sorting technique
array[r] = array[i+1]
in computer science which is based on
divide and conquer algorithm. In this array[i+1] = temp
algorithm, we find a pivot element of the return i+1
list through some logic and then divide the
array around the pivot. After applying the }
pivot algorithm, the elements on the left of
it are always smaller than it while those on
the right are always greater. Procedure:-
● First we create an array and insert
elements randomly in it and call the
Algorithm – sort function.
Algorithm of quick sort – ● Then the sort function each time calls
the partition function.
QuickSort(array, low, high) ● In the partition function we create a
If low < high then pivot element which is generally the
first element of the array and we
pivot = partition(array, low,
create integers i=l and j=r where i
high)
points to the first element and j to the
QuickSort(array, low, pivot-1) last. Now we run a loop till I <j in
which we first compare the ith
QuickSort(array, pivot+1, high)
element with pivot and similarly the
} jth. while the ith element is less than
or equal to pivot we increament i
pointer and while the jth is greater(>)
partition(array, low, high){ than pivot we decrement j.
pivot = array[r] ● Now we swap the elements using
swap(a,i,j) if i<j where a is the array .
i = l-1
● If i>=j then we swap the pivot element
for j in range(l,r): with the element at the jth position
and thus the pivot element gets its
if array[j] < pivot:
desired position in the sorted array
i += 1 and then in the end we return j which
temp = array[j] is used by the sort function to again
call the partition function till l<r.
    for (int x = 0; x < 1500; x += 100)
Code:-     {
#include <iostream>         int time = 0;
#include <chrono>         int a[100 + x];
using namespace std::chrono;        
using namespace std;         for (int j = 0; j < 50; j++)
void swap(int a[], int p, int q)         {
{ for (int i = 0; i < x + 100; i++)
    int t = a[p];         {
    a[p] = a[q];             a[i] = rand() % (101 + x);
    a[q] = t;             /* code */
}         }
int partition(int a[], int l, int r)             auto start =
{ steady_clock::now();
            sort(a, 0, 100 + x - 1);
    int pivot = a[l];             auto end = steady_clock::now();
    int i = l, j = r;             auto duration =
    while (i < j) duration_cast<nanoseconds>(end - start);
    {
            time = time + duration.count();
        while (a[i] <= pivot)         }
        {  cout<<100+x<<" ,"<<time/50<<endl;       /*
            i++; code */
            /* code */     }
        } }
        while (a[j] > pivot) Output:-
        {
            /* code */ j--;
        }
        if (i < j)
        {
            swap(a, i, j);
            /* code */
        }
        else
        {
            swap(a, l, j);
        }
    }
    return j;
}
void sort(int a[], int l, int r)
{
    if (l < r)
    {
        int m = partition(a, l, r);
        sort(a, l, m - 1);
        sort(a, m + 1, r); /* code */
    }
Graph:-
    return;
}
int main()
{
Result:-
As the size of the array increases the
time taken to sort the array using quick
sort function also increases. There is dip
at some places due to background
processes thus leading to increased time
in other areas.

Conclusion –
From this experiment, we concluded that
the best case and average case time
complexity of quick sort is O(nlogn) whereas
the worst case time complexity is O(n^2).
#include <iostream>
Task:-Randomised Quick #include <chrono>
using namespace std::chrono;
Sort using namespace std;
void swap(int a[], int p, int q)
{
Procedure:-     int t = a[p];
    a[p] = a[q];
● First we create an array and insert     a[q] = t;
}
elements randomly in it and the we
int partition(int a[], int l, int r)
swap two elements randomly and {
then call the sort function.
    int pivot = a[l];
● Then the sort function each time     int i = l, j = r;
calls the partition function.     while (i < j)
    {
● In the partition function we create a
pivot element which is generally the         while (a[i] <= pivot)
first element of the array and we         {
            i++;
create integers i=l and j=r where i             /* code */
points to the first element and j to         }
the last. Now we run a loop till I <j in         while (a[j] > pivot)
        {
which we first compare the ith             /* code */ j--;
element with pivot and similarly the         }
        if (i < j)
jth. while the ith element is less than         {
or equal to pivot we increament i             swap(a, i, j);
pointer and while the jth is             /* code */
        }
greater(>) than pivot we decrement         else
j.         {
            swap(a, l, j);
● Now we swap the elements using
        }
swap(a,i,j) if i<j where a is the array     }
.     return j;
}
● If i>=j then we swap the pivot void sort(int a[], int l, int r)
element with the element at the jth {
    if (l < r)
position and thus the pivot element
    {
gets its desired position in the sorted         int m = partition(a, l, r);
array and then in the end we return         sort(a, l, m - 1);
        sort(a, m + 1, r); /* code */
j which is used by the sort function     }
to again call the partition function     return;
till l<r. }
int main()
{
    for (int x = 0; x < 1500; x += 100)
    {
Code:-         int time = 0;
        int a[100 + x];
       
        for (int j = 0; j < 50; j++)
        {
for (int i = 0; i < x + 100; i++)
        {
            a[i] = rand() % (101 + x);
            /* code */
        }
        int k=(1500)%(100+x);
        swap(a,0,k);
            auto start =
steady_clock::now();
            sort(a, 0, 100 + x - 1);
            auto end = Learnings –
steady_clock::now();
            auto duration = This experiment gave us an insight on the
duration_cast<nanoseconds>(end - start);
how the time complexity of the
            time = time + randomized quick sort varies as the size of
duration.count(); the list increases. From this experiment,
        }
 cout<<100+x<<" ,"<<time/50<<endl;       we learnt about the relationship between
/* code */ the time taken by the randomized quick
    }
}
sort algorithm and the size of list. We also
learned how the background processes
Output:-
interfere in the analysis of the algorithm
and the various other factors that leads to
inconsistencies.

Conclusion:-
We conclude that the best case time
complexity of this sorting will be O(log(n))
and the worst case time complexity will
beO(N^2).

Graph:-
Algorithm for Prim’s :-
Algorithm Prim(E, cost, n, t)
//E is the set of edges in G. cost[1:n, //1:n]
Task:-Prim’s Algorithm is the cost adjacency matrix of //an n
Introduction:- vertex graph such that cost[i,j] //is either a
positive real number or //infinity if no
Prim's algorithm is a greedy algorithm that edge (i,j) exists. A //minimum spanning
finds a minimum spanning tree for a weighted tree is //computed and stored as a set of
undirected graph. This means it finds a subset
//edges in the array t[1:n-1, 1:2]. //(t[i,1],
of the edges that forms a tree that includes
t[i,2]) is an edge in the //minimum-cost
every vertex, where the total weight of all the
edges in the tree is minimized.
spanning tree. The //final cost is returned.
{
Procedure:-
Let (k,l) be an edge of minimum cost in
● First we create a 2-d array(cost-adjacency
E;
matrix) which stores the weights between
various edges and the edges which aren’t mincost := cost[k,l]
connected the corresponding element of
matrix stores INT16_MAX which points to t[1,1] := k, t[1,2] := l;
infinity.
● Then we create a
for I := 1 to n do // Initialize near.
vector<pair<int,<pair<int,int>>>mst to if (cost[i,l] < cost[i,k]) then near[i] := l;
store the edges and corresponding
weights of the required mst to be formed. else near[i] := k;
● Then we first find the min weight edge in
the matrix and store corresponding edges
near[k] := near[l] := 0;
in k and l.Then we create a near array and
store the closer edge I.e. k or l to other
edges. for i := 2 to n-1 do
● Now we modify near array for k and l
elements as they have been selected and
{//Find n-2 additional edges for t.
inserted in mst. Let j be an index such that near[j]
● Now we will select a minimum weight
edge in the near array and also such that != 0 and cost[j,near[j]] is
it is not visited and inserted in mst yet.
Then we add that edge in the mst and now minimum;
we again update the near array. t[i,1] := j; t[i,2] := near[j];
● We do this until we get our final mst with
v vertices and v-1 edges in the result. mincost := mincost +
cost[j,near[j]];

Algorithm – near[j] := 0
for k := 1 to n do // Update near[]     mst.push_back(make_pair(mi,
make_pair(k, l)));
if((near[k]!=0) and     int near[v];
   
(cost[k,near[k]] > cost[k,j])) then    
    min_weight = min_weight + mi;
near[k] := j;     for (int i = 0; i < v; i++)
    {
}         if (a[i][k] > a[i][l])
        {
return mincost;             near[i] = l;
            /* code */
}         }
        else
        {
        }

Code:-
        /* code */
#include <bits/stdc++.h>     }
using namespace std;     near[k] = k;
int main()     near[l] = l;
{     for (int i = 0; i < v ; i++)
    int v, e, k, l, mi = INT16_MAX,     {
min_weight = 0;         mi = INT16_MAX;
    cin >> v >> e;         int index;
    vector<pair<int, pair<int, int>>> mst;         for (int j = 0; j < v; j++)
    int a[v][v];         {
    for (int i = 0; i < v; i++)             if (near[j] != j )
    {             {
        for (int j = 0; j < v; j++)                 if (mi > a[near[j]][j])
        {                 {
            a[i][j] = INT16_MAX;                     mi = a[near[j]][j];
            /* code */                     index = j;
        }                     /* code */
                }
        /* code */             }
    }             /* code */
    for (int i = 0; i < e; i++)         }
    {         min_weight = min_weight + mi;
        int x, y, w;
        cin >> x >> y >> w;         mst.push_back(make_pair(mi,
        a[x][y] = w; make_pair(index, near[index])));
        a[y][x] = w;         near[index] = index;
        if (mi > w)         for (int k = 0; k < v; k++)
        {         {
            mi = w;             if ((a[k][near[k]] >
            k = x; a[k][index])&&near[k]!=k)
            l = y;             {
            /* code */                 near[k] = index;
        }                 /* code */
            }
        /* code */
    }             /* code */
        }

        /* code */
    }
for (int i = 0; i < v-1; i++)
{cout<<mst[i].first<<"
"<<mst[i].second.first<<"
"<<mst[i].second.second<<endl;

    /* code */
}

} Required MST:-

Input:-

Learnings –
Prim's Algorithm reorders its input in order to
choose the cheapest edge. We say that Prim's
Algorithm is an adaptive greedy algorithm; in the
sense that, at every iteration, the algorithm tries
Graph(diagram):- to readjust the input to its own convenience.

Output:-
one specific starting node to all other nodes of a
graph. It is different from the minimum spanning
tree as the shortest distance among two vertices
might not involve all the vertices of the graph.
It is important to note that Dijkstra’s algorithm is
only applicable when all weights are positive
because, during the execution, the weights of the
edges are added to find the shortest path.

Procedure:-
● First we create a 2-d array(cost-adjacency
matrix) which stores the weights between
various edges and the edges which aren’t
connected the corresponding element of
matrix stores INT16_MAX which points to
infinity.
● Then we create two arrays visited and
distance to check whether that element
has been visited and its smallest distance
respectively. . We store different vertices
distances from the root in the distance
array.
● Now we iterate the array and find the
Task:-Dijkstra’s element with shortest distance from the
root element such that it has not been
Algorithm(Single root visited.
● Now we compare all the vertices distance
shortest path algo) from the root array that are connected to
selected vertex and modify the distance
array respectively.
Intoduction:-
Code:-
This algorithm makes a tree of the shortest path #include <bits/stdc++.h>
from the starting node, the source, to all other using namespace std;
nodes (points) in the graph .Dijkstra's algorithm int main()
{
makes use of weights of the edges for finding the     int v, e;
path that minimizes the total distance (weight)     cin >> v >> e;
among the source node and all other nodes. This     int a[v][v];
    for (int i = 0; i < v; i++)
algorithm is also known as the single-source
    {
shortest path algorithm.         for (int j = 0; j < v; j++)
Dijkstra’s algorithm is the iterative algorithmic         {
process to provide us with the shortest path from             a[i][j] = INT16_MAX;
            /* code */
        }                 /* code */
            }
        /* code */
    }             /* code */
    for (int i = 0; i < e; i++)         }
    {
        int x, y, w;         /* code */
        cin >> x >> y >> w;     }
        a[x][y] = w;
        a[y][x] = w;     for (int i = 0; i < v; i++)
        /* code */     {
    }         cout << dis[i] << " ";
    int visited[v];         /* code */
    int dis[v];     }
    for (int i = 0; i < v; i++) }
    {
        visited[i] = -1;
        dis[i] = a[0][i];
        /* code */ Input:-
    }
    visited[0] = 0;
    dis[0] = 0;
    for (int i = 0; i < v; i++)
    {
        int mi = INT16_MAX, index;
        for (int j = 0; j < v; j++)
        {
            if (visited[j] == -1)
            {
                if (mi > dis[j])
                {
                    mi = dis[j];
                    index = j;
                    /* code */ Graph(diagram):-
                }

                /* code */
            }

            /* code */
        }
        visited[index] = 0;
        for (int j = 0; j < v; j++)
        {
            if (a[index][j] != INT16_MAX)
            { Output:-
                if (dis[j] > dis[index] +
a[index][j])
                {
                    dis[j] = dis[index] +
a[index][j];
                    /* code */
                }
● Using the time module I have calculated the time for
strassen multiplication and normal multiplication.

Code:-
#include<iostream>
#include<vector>
using namespace std;
vector<vector<int>>
multiply(vector<vector<int>>a,vector<vecto
r<int>>b){
    vector<vector<int>>
mul(a[0].size(),vector<int>(a[0].size(),0)
);
Task:- STRASSEN’s     for(int i=0;i<a[0].size();i++){
        for(int j=0;j<a[0].size();j++){

MATRIX             for(int
k=0;k<a[0].size();k++){
               
MULTIPLICATION mul[i][j]+=(a[i][k]*b[k][j]);
            }
OBJECTIVE :         }
    }
Time analysis of strassen’s matrix multiplication.     return mul;
}

PROCEDURE : vector<vector<int>>
add(vector<vector<int>>a,vector<vector<int
● In this, first of all I have used a for loop for iterating >>b){
over the dimensions of the matrix.     vector<vector<int>>
c(a[0].size(),vector<int>(a[0].size(),0));
● Then for each dimension, I have created matrices of     for(int i=0;i<a[0].size();i++)
random values using the generateArray() function.         for(int j=0;j<a[0].size();j++)
            c[i][j]=a[i][j]+b[i][j];
● Then split the matrix into smaller matrices using the
    return c;
split() function.
}
vector<vector<int>>     e=split(B,0,0,n);
sub(vector<vector<int>>a,vector<vector<int     f=split(B,0,n/2,n);
>>b){     g=split(B,n/2,0,n);
    vector<vector<int>>     h=split(B,n/2,n/2,n);
c(a[0].size(),vector<int>(a[0].size(),0));
    for(int i=0;i<a[0].size();i++)     vector<vector<int>>
        for(int j=0;j<a[0].size();j++) p1(n/2,vector<int>(n/2)),p2(n/2,vector<int
            c[i][j]=a[i][j]-b[i][j]; >(n/2)),p3(n/2,vector<int>(n/2)),p4(n/2,ve
    return c; ctor<int>(n/2)),p5(n/2,vector<int>(n/2)),p
} 6(n/2,vector<int>(n/2)),p7(n/2,vector<int>
(n/2));
void     p1=strassen_multiply(a,sub(f,h));
copy(vector<vector<int>>&temp,vector<vecto     p2=strassen_multiply(add(a,b),h);
r<int>>&ans,int si,int sj,int n){     p3=strassen_multiply(add(c,d),e);
    for(int i=0;i<n/2;i++)     p4=strassen_multiply(d,sub(g,e));
        for(int j=0;j<n/2;j++)    
            ans[si+i][sj+j]=temp[i][j]; p5=strassen_multiply(add(a,d),add(e,h));
}    
p6=strassen_multiply(sub(b,d),add(g,h));
vector<vector<int>>split(vector<vector<int    
>>a,int si,int sj,int n){ p7=strassen_multiply(sub(a,c),add(e,f));
    vector<vector<int>>
x(n/2,vector<int>(n/2));     a=add(sub(add(p5,p4),p2),p6);
    for(int i=0;i<n/2;i++)     b=add(p1,p2);
        for(int j=0;j<n/2;j++)     c=add(p3,p4);
            x[i][j]=a[i+si][j+sj];     d=sub(sub(add(p1,p5),p3),p7);

    return x;    
} vector<vector<int>>ans(n,vector<int>(n));
    copy(a,ans,0,0,n);
vector<vector<int>>     copy(b,ans,0,n/2,n);
strassen_multiply(vector<vector<int>>A,vec     copy(c,ans,n/2,0,n);
tor<vector<int>>B){     copy(d,ans,n/2,n/2,n);
    int n=A[0].size();
    if(n==1){     return ans;
        }
vector<vector<int>>x(1,vector<int>(1,A[0][
0]*B[0][0])); int main(){
        return x;     int n;
    }     cin>>n;
    vector<vector<int>>    
a(n/2,vector<int>(n/2)),b(n/2,vector<int>( vector<vector<int>>a(n,vector<int>(n)),b(n
n/2)),c(n/2,vector<int>(n/2)),d(n/2,vector ,vector<int>(n));
<int>(n/2));     for(int i=0;i<n;i++)
    vector<vector<int>>         for(int j=0;j<n;j++)
e(n/2,vector<int>(n/2)),f(n/2,vector<int>(             cin>>a[i][j];
n/2)),g(n/2,vector<int>(n/2)),h(n/2,vector
<int>(n/2));     for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
    a=split(A,0,0,n);             cin>>b[i][j];
    b=split(A,0,n/2,n);
    c=split(A,n/2,0,n);
    d=split(A,n/2,n/2,n);
   
vector<vector<int>>mul=strassen_multiply(a
,b);
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++)
            cout<<mul[i][j]<<" ";
        cout<<endl;
    }
}

Input:-

Output:-

OBSERVATION : As we can observe from the


graph, for smaller sizes of matrices time for normal
multiplication is lesser compared to strassen
multiplication. It is because of the increased number
of additions in Strassen's method as it adds more to
the time compared to the decrease in time due to
lesser number of multiplications. But at larger
dimensions, the major point in time consideration is
the number of multiplications. As we know in
strassen’s there are 7 multiplications while 8 in case of
normal multiplication. Therefore time for strassen’s is
less than that of normal multiplication.
can never be optimal. Such solutions provide sub
Task:-Fractional optimal solutions because although they pass the
feasibility criterion but they are not fulfilling the
Knapsack(greedy objective function. The best technique is to sort
the list on the basis of their P/W and then fill in
approach) the bag with until no item is left or the bag fills up
to maximum capacity.

Objective:- Algorithm:-
The objective of our experiment is to devise a while (m > 0)
greedy approach to solve the knapsack problem
such that the output is an array having fraction of
{
each article included in the bag. if (w[i] <= m){

Introduction:- m = m - w[i]

The knapsack problem or more formally, b[i] = 1;


fractional knapsack problem is a problem which
q = q + a[i].first * w[i];
can be solved by greedy algorithm. The problem
statement of the knapsack is that we are given a i--;
knapsack of given size and some objects n of given
weight. Each object has some profit which we will }
get if the object is added to the bag. We need to else
fill the knapsack by adding these objects to the
knapsack, completely or fractionally, such that the {
net profit we get is maximized. From the problem
statement it is clear that it is an optimization b[i] = m / w[i];
problem in which we have to maximize the profit, q = q + a[i].first * m;
thus it can be solved using the greedy technique
of algorithm design. The idea behind maximizing i--;
the profit is to obtain the profit by weight ratio of
each object and then sort the list in decreasing
}
order. After that we will pick the item and fill the }
bag until either we are left with no items or the
bag gets completely filled. The greedy technique Procedure:-
of algorithm design generally consists of an
objective function and a feasibility criterion. Here
in case of the knapsack problem, the objective
● First we take input of weight and the
respective profit array.
function is to maximize the net profit obtain
whereas the feasibility criterion is that the net ● Then we store the profit per unit weight
weight of the bag should never exceed its ration and respective weight in a vector
capacity. There are various techniques of solving pair.
the problems which can pass the feasibility
criterion like choosing the item with minimum
● The we sort the vector pair such that we
weight or selecting an item with maximum profit have the profits in decreasing order.
but the profit obtained through these approaches
● Now we keep on adding the weight as per
}
the capacity in the knapsack.
● If the given weight will be more than the
current capacity of the knapsack then we
will add fractional weight.
● Our main objective is to maximize the Learnings –
profit.
From this experiment we learnt the greedy technique
Code:- of algorithm design. This problem of knapsack gave us
an insight on how the greedy algorithm are designed,
#include <bits/stdc++.h> framed and how they work. We learnt how to think
#include <vector> about the greedy logic and after that turn the logic
using namespace std; into code by implementing it. We learnt how this
int main() technique works on optimization problems like finding
{
the maximum or minimum value.
    int n;
    cin >> n;
    vector<pair<int, int>> a;
    int p[n], w[n];
    for (int i = 0; i < n; i++)
Conclusion –
    { From this experiment, we learnt how to solve a greedy
        cin >> w[i] >> p[i]; problem of fractional knapsack and other similar
       
problems. Here we can conclude that for optimization
a.push_back(make_pair(float(float(p[i]) /
based solutions greedy technique of algorithm design
float(w[i])), w[i]));
        sort(a.begin(), a.end()); is a good technique.
    }
    int m, i = n-1;
    float q = 0.0;
    cin >> m;
    vector<float> b(n, 0);

    while (m > 0)
    {
        if (w[i] <= m){
            m = m - w[i];
        b[i] = 1; /* code */
        q = q + a[i].first * w[i];
        i--;
    }
    else
    {
        b[i] = m / w[i];
        q = q + a[i].first * m;
    i--;
    }
    }
for (int i = 0; i < n; i++)
{cout<<b[i]<<" ";
    /* code */
}
● Then we update the solution matrix
Task:-Floyd-Warshall by considering all vertices as an
Algorithm intermediate vertex.
● The idea is to one by one pick all
Objective :- To find shortest distances vertices and updates all shortest
between every pair of vertices in a given paths which include the picked
edge weighted directed Graph. vertex as an intermediate vertex in
the shortest path.
Introduction:- ● When we pick vertex number k as an
Floyd-Warshall Algorithm is an algorithm intermediate vertex, we already
for finding the shortest path between all have considered vertices {0, 1, 2, ..
the pairs of vertices in a weighted graph. k-1} as intermediate vertices. 
This algorithm works for both the directed Code:-
and undirected weighted graphs. But, it
#include <bits/stdc++.h>
does not work for the graphs with using namespace std;
negative cycles (where the sum of the int main()
edges in a cycle is negative). {
    int v, e;
    cin >> v >> e;
Algorithm:-     int a[v][v];
    for (int i = 0; i < v; i++)
Algorithm of Floyd washall –     {
        for (int j = 0; j < v; j++)
for (int k = 0; k < v; k++)
        {if (i==j)
{         {a[i][j]=0;
            /* code */
for (int i = 0; i < v; i++)         }
       
{             else{a[i][j] = INT16_MAX;}
            /* code */
for (int j = 0; j < v; j++)         }
{
        /* code */
a[i][j] = min(a[i][j], a[i][k] + a[k][j]);     }
    for (int i = 0; i < e; i++)
}     {
        int x, y, w;
}         cin >> x >> y >> w;
        a[x][y] = w;
}         /* code */
    }
Procedure:-     for (int k = 0; k < v; k++)
    {
● We initialize the solution matrix         for (int i = 0; i < v; i++)
same as the input graph matrix as a         {
            for (int j = 0; j < v; j++)
first step.             {
                a[i][j] = min(a[i][j],
a[i][k] + a[k][j]);
            }
            /* code */
        }

        /* code */
    }
    for (int i = 0; i < v; i++)
    {
        for (int j = 0; j < v; j++)
        {
            if (a[i][j] == INT16_MAX)
            { Conclusion –
                cout << "INF"
                     << " "; Time Complexity : O(n3)
                /* code */
            }
            else
            {
                cout << a[i][j] << " ";
            }

            /* code */
        }
cout << endl;
        /* code */
    }
   
}

Input:-

Output:-
takes an entry time ei and exit time
xi which may be different for the two lines.

Algorithm:-
 for (i = 1; i < NUM_STATION; ++i) 
    { 
        T1[i] = min(T1[i - 1] + a[0][i], 
Task:-Assembly line                     T2[i - 1] + t[1][i] + a[0][i]); 
Algorithm         T2[i] = min(T2[i - 1] + a[1][i],
                    T1[i - 1] + t[0][i] + a[1][i]); 
Objective : To find minimum time to     } 
pass through the two assembly lines.

Introduction : A car factory has two Code :-


assembly lines, each with n stations. A
#include <bits/stdc++.h>
station is denoted by Si,j where i is either 1 using namespace std;
or 2 and indicates the assembly line the int main()
{
station is on, and j indicates the number of
    int n;
the station. The time taken per station is     cin >> n;
denoted by ai,j. Each station is dedicated to     int a[2][n];
    int t[2][n];
some sort of work like engine fitting, body     for (int i = 0; i < 2; i++)
fitting, painting, and so on. So, a car     {
chassis must pass through each of the n         for (int j = 0; j < n; j++)
        {
stations in order before exiting the factory.             cin >> a[i][j];
The parallel stations of the two assembly            
        }
lines perform the same task. After it passes     }
through station Si,j, it will continue to     for (int i = 0; i < 2; i++)
station Si,j+1 unless it decides to transfer to     {
        for (int j = 0; j < n; j++)
the other line. Continuing on the same line         {
incurs no extra cost, but transferring from             cin >> t[i][j];
        }
line i at station j – 1 to station j on the
    }
other line takes time ti,j. Each assembly line  int e1,e2,x1,x2;
 cin>>e1>>e2>>x1>>x2;
 int result[2][n];
 int t1=e1+a[0][0],t2=e2+a[1][0];
Conclusion:-
 result[0][0]=t1,result[1][0]=t2;
 for (int i = 1; i < n; i++)
Time Complexity : O(n)
 {result[0][i]=min(t2+t[1][i]+a[0][i],t1+a
[0][i]);
 result[1][i]=min(t1+t[0][i]+a[1][i],t2+a[
1][i]);
 t1=result[0][i];
 t2=result[1][i];
   
 }
result[0][n-1]+=x1;
result[1][n-1]+=x2;
cout<<min(result[0][n-1],result[1][n-1])<<
endl;
}

Input :-

Output:-

Graph :
convention, we consider source at stage 1
and destination as last stage.

Algorithm:-
for (int i = 0; i < e; i++)
{
int x, y, w;
cin >> x >> y >> w;
a[x][y] = w;
if (y==destination)
{distance[x]=w;
}
}

for (int i = 0; i < v-2; i++)


{for(int j=0;j<v;j++){
for(int k=0;k<v;k++){
Task:-Multistage-graph if
Problem Algorithm (a[j][k]!=INT16_MAX&&distance[k]!=INT1
6_MAX)
Objective : To find shortest path from {
source to destination in multistage graph.

Introduction : A Multistage graph is a distance[j]=min(distance[j],distance[k]+a[j]


directed graph in which the nodes can be [k]);
divided into a set of stages such that all }
edges are from a stage to next stage only
}
(In other words there is no edge between
vertices of same stage and from a vertex of } }
current stage to previous stage).
We are given a multistage graph, a source
and a destination, we need to find shortest Code :-
path from source to destination. By
#include<bits/stdc++.h>    
using namespace std;     cout<<distance[source]<<endl;
int main(){ }
    int v,e;
    cin>>v>>e;
    int a[v][v];
    int distance[v]; INPUT :-
    for (int i = 0; i < v; i++)
    {distance[i]=INT16_MAX;
        /* code */
    }

    int source,destination;
    cin>>source>>destination;
    distance[destination]=0;
    for (int i = 0; i < v; i++)
    {
        for (int j = 0; j < v; j++)
        {
            a[i][j] = INT16_MAX; OUTPUT:-
            /* code */
        }

        /* code */
    }
    for (int i = 0; i < e; i++)
    {
        int x, y, w;
        cin >> x >> y >> w;
        a[x][y] = w;
    if (y==destination)
    {distance[x]=w;
       
    }
        Graph :
       
    }

    for (int i = 0; i < v-2; i++)


    {for(int j=0;j<v;j++){
        for(int k=0;k<v;k++){
            if
(a[j][k]!=INT16_MAX&&distance[k]!=INT16_MA
X)
            {
               
distance[j]=min(distance[j],distance[k]+a[
j][k]);
            }
           
        } Time Complexity : O(n3)
    }
       
    }
Given a connected undirected graph, a
spanning tree of that graph is a subgraph
that is a tree and connects all the vertices
together. A minimum spanning tree for a
weighted, connected and undirected graph
is a spanning tree with a weight less than
or equal to ever other possible spanning
tree. In Kruskal we start with an empty
tree. Sort all the edges of the given graph
in ascending order of weights. Then pick
the edge with the minimum cost and check
if on adding it to the current MST does it
creates a cycle. If it does, ignore it,
otherwise add it to the graph. Do this till
all the vertices are covered. The graph
obtained this way is the MST.

PROCEDURE :
● First, sort all the edges from low
weight to high.
● Now, take the edge with the lowest
weight and add it to the spanning
tree.
● If the edge to be added creates a
cycle, then reject the edge.
● Continue to add the edges until we
reach all vertices, and a minimum
spanning tree is created.

The applications of Kruskal's algorithm


Task:-Kruskal’s are :

Algorithm Kruskal's algorithm can be used to layout


electrical wiring among cities. It can be
Introduction : used to lay down LAN connections.

The Kruskal’s algorithm is a very famous Code :


greedy approach to obtain a minimum
#include <bits/stdc++.h>
spanning tree (MST) out of a given using namespace std;
connected undirected weighted graph.
int find_set(int x, vector<set<int>> &s)     cout << MST[i].first << " " <<
{ MST[i].second << endl;
  for (int i = 0; i < s.size(); i++)   cout << "Mincost = " << mincost << endl;
  { }
    if (s[i].find(x) != s[i].end())
      return i;
  }
  return -1;
} INPUT:-
int main()
{
  int n, e;
  cin >> n >> e;
  vector<pair<int, pair<int, int>>> edges;
  edges.reserve(e);
  for (int i = 0; i < e; i++)
  {
    int x, y, c;
    cin >> x >> y >> c;
    edges.push_back({c, {x, y}});
  }
OUTPUT:-
  sort(edges.begin(), edges.end());

  vector<set<int>> s(n);
  for (int i = 0; i < n; i++)
    s[i].insert(i);

  int mincost = 0;
  vector<pair<int, int>> MST;

  for (int i = 0; i < n && MST.size() != n


- 1; i++)
  {
    int a =
find_set(edges[i].second.first, s);
    int b =
find_set(edges[i].second.second, s);
    if (a == b)
      continue;
    set<int> temp;
Graph:-
    set_union(s[a].begin(), s[a].end(),
s[b].begin(), s[b].end(), inserter(temp,
temp.begin()));
    s[a] = temp;
    s[b].clear();
    MST.push_back({edges[i].second.first,
edges[i].second.second});
    mincost += edges[i].first;
  }
  cout << "MST  :" << endl;
  for (int i = 0; i < MST.size(); i++)
1. Pick edge 7-6: No cycle is formed,
include it. 
 

2. Pick edge 8-2: No cycle is formed,


include it. 
 
5. Pick edge 2-5: No cycle is formed,
include it. 
 

3. Pick edge 6-5: No cycle is formed,


include it. 
  6. Pick edge 8-6: Since including this edge
results in the cycle, discard it.
7. Pick edge 2-3: No cycle is formed,
include it. 
 

4. Pick edge 0-1: No cycle is formed,


include it. 
 
8. Pick edge 7-8: Since including this edge
results in the cycle, discard it.
9. Pick edge 0-7: No cycle is formed,
include it. 
 
Task:-0/1 Knapsack
Problem
Objective : To get the maximum profit
in the knapsack of capacity W by filling
given weights and profits of n items.

10. Pick edge 1-2: Since including this edge Introduction : Given weights and
results in the cycle, discard it. values of n items, put these items in a
11. Pick edge 3-4: No cycle is formed, knapsack of capacity W to get the
include it.  maximum total value in the knapsack. In
  other words, given two integer arrays
val[0..n-1] and wt[0..n-1] which represent
values and weights associated with n
items respectively. Also given an integer W
which represents knapsack capacity, find
out the maximum value subset of val[]
such that sum of the weights of this subset
is smaller than or equal to W. You cannot
Since the number of edges included equals break an item, either pick the complete
(V – 1), the algorithm stops here. item or don’t pick it (0-1 property).
Conclusion:-
Algorithm:-
Time Complexity : O(E logV)
int knapSack(int W, int wt[], int val[], int n)
E is the number of edges and V is the
{
number of vertices.
int i, w;
We learnt the greedy technique of
algorithm design. We learnt how to vector<vector<int>> K(n + 1,
implement the Kruskal’s algorithm and vector<int>(W + 1));
how to find the MST for a given connected
for (i = 0; i <= n; i++)
undirected weighted graph.
{
for (w = 0; w <= W; w++)
{
if (i == 0 || w == 0)
K[i][w] = 0;
else if (wt[i - 1] <= w) int main()
{int p;
K[i][w] = max(val[i - 1] + cin>>p;
  int val[p] ;
K[i - 1][w - wt[i - 1]],   int wt[p];
for (int i = 0; i < p; i++)
K[i - 1][w]); {cin>>val[i];
    /* code */
else }
for (int i = 0; i < p; i++)
K[i][w] = K[i - 1][w]; {cin>>wt[i];
    /* code */
} }

}
  int W ;
return K[n][W];   cin>>W;
  int n = sizeof(val) / sizeof(val[0]);
}
  cout << "Max Profit is: " << knapSack(W,
wt, val, n);
Code :
  return 0;
#include <bits/stdc++.h>
}
using namespace std;

int max(int a, int b)


{
  return (a > b) ? a : b; INPUT:-
}

int knapSack(int W, int wt[], int val[],


int n)
{
  int i, w;
  vector<vector<int>> K(n + 1,
vector<int>(W + 1));
  for (i = 0; i <= n; i++)
  {
    for (w = 0; w <= W; w++) OUTPUT:-
    {
      if (i == 0 || w == 0)
        K[i][w] = 0;
      else if (wt[i - 1] <= w)
        K[i][w] = max(val[i - 1] +
                          K[i - 1][w -
wt[i - 1]],
                      K[i - 1][w]);
      else
        K[i][w] = K[i - 1][w];
    }
  } Conclusion:-
  return K[n][W];
} Time Complexity : O(N*W)
Task:N-Queen problem
The idea of n queen problem is to place
queens one by one in different columns
starting from the leftmost one.When we
place a queen in a column we check that
the already placed other queens and
currently place queen do not attack each
other when placed in a NXN chessboard.If
in the current column we find a row for
which they don’t attack we mark this row
and column as a part of the solution.If we
don’t find such a row we backtrack and
return false.

Procedure:
● Start from the leftmost column
● If all queens are placed return true.
● Try all rows in the current column
● Do the following for every tried row.
● if the queen can be placed safely in Algorithm:-
this row then mark this row and void n_queen(int n, vector<vector<int>>
column as part of the solution and &a, set<int> &s,set<int>&s2, set<int> &c,
recursively check if placing queen leads int i, stack<int>&st,int &count)
to the a solution o r not
{
● if placing the queen in this row and
column leads to a solution return true. for (int k = 0; k < n; k++)
{
● if placing queen doesn’t lead to a
solution then unmark this row and
column and backtrack to other
int p = 0;
solutions
if (c.find(k) == c.end() && s.find(k - i)
● If all rows have been tried and nothing
== s.end() && s2.find(k + i) == s2.end())
worked, return false to trigger
backtracking {
a[i][k] = 1
s.insert(k - i) #include <bits/stdc++.h>
using namespace std;
s2.insert(i + k) void n_queen(int n, vector<vector<int>>
&a, set<int> &s,set<int>&s2, set<int> &c,
c.insert(k) int i, stack<int>&st,int &count)
{
st.push(k)     for (int k = 0; k < n; k++)
    {
count--;
        int p = 0;
        if (c.find(k) == c.end() &&
s.find(k - i) == s.end() && s2.find(k + i)
n_queen(n, a, s,s2, c, i + 1, st,count); == s2.end())
        {
}             a[i][k] = 1;
           
if(count==0){             s.insert(k - i);
            s2.insert(i + k);
return;             c.insert(k);
            p = 1;
}             st.push(k);
count--;
if (k == n - 1 )      
            n_queen(n, a, s,s2, c, i + 1,
{ st,count);
        }
count++;         if(count==0){
   
        return;
    }
a[i - 1][st.top()] = 0;         if (k == n - 1 )
        {
count++;

c.erase(st.top());             a[i - 1][st.top()] = 0;


           
s.erase(st.top() - (i - 1));             c.erase(st.top());
            s.erase(st.top() - (i - 1));
s2.erase(i - 1 + st.top());             s2.erase(i - 1 + st.top());
         
            st.pop();
           
st.pop();         }
    }
}
int main()
} {
    int n;
}     cin >> n;
    vector<vector<int>> a(n,
} vector<int>(n, 0));
    set<int> s,s2, c;
Code:-     int p = n;
 stack<int>st;
    n_queen(n, a, s,s2, c, 0, st,p);
   
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {
            cout << a[i][j] << " ";
        }
        cout << endl;
    }
}

Input/Output:

Analysis:
The time complexity is
O(n^2) because we are
selecting if we can put or not
put a Queen at that place.
The space is the board size
times the result.
● If no colour is assigned this means
Task:-Graph Colouring given colours are not enough to
Problem colour the graph.
● Else the function call for the next
The idea is to assign colors one by one to value of k i.e. the next node will
different vertices starting from the vertex occur.
0.before assigning a color check for safety
by considering already assigned colors to
the adjacent vertices.If the arrangement Algorithm:
does not violate the conditions mark the
m_color( a,gp, n, c, p, k)
assignment as part of the solution.If not
then backtrack and return false. {

Procedure: for ( i = 0; i < c; i++)


{
● Firstly, input the number of colours
with which we want to colour the if (k == n || p ==1)
nodes of the graph.
then
● Then take the cost adjacency matrix
having value 1 if there is an edge return;
between two nodes and 0 if not.
● Then take a colour vector/array and
initialise all of its values to 0. It will a[k] = i;
store the sequence in which the int m = 0;
nodes will be coloured.
● Pass the first node from which for ( j = 0; j < gp[k].size(); j++)
colouring is to start, no of colours, {
colour vector and the cost adjacency
matrix to the mcoloring function. if ( gp[k][j] == 1)
● Here if the value of the node passed then
is equal to the no of nodes then it’s
the last node to be coloured so {if(a[j]==i){
simply print the colouring array. then
● Otherwise move ahead and go to
m = 1;
the next_value function where a
colour which is safe as per the break;}
constraints will be assigned to the
}
node.
}
if (m == 1 && i == c - 1)
{     }
}
p = 1; int main()
{
}     int n, c, p = 0,e;
    cin >> n >> e>>c;
if (m == 0)     vector<int> a(n, -1);
   
{ vector<vector<int>>gp(n,vector<int>(n,0));
    for(int i=0;i<e;i++){
k++;         int x,y;
        cin>>x>>y;
m_color(a,gp, n, c, p, k);         gp[x][y]=1;
        gp[y][x]=1;
}     }
    int k = 0;
}     m_color(a, gp,n, c, p, k);
    if (p == 1)
}     {
        cout << "Not Possible" << endl;
    }
Code:-     else
#include <bits/stdc++.h>     {cout<<"nodes     colours"<<endl;
using namespace std;         for (int i = 0; i < n; i++)
void m_color(vector<int>         {
&a,vector<vector<int>>gp, int n, int c,             cout << i << "     -->  
int &p, int &k)  "<<a[i]<<endl;
{         }
    for (int i = 0; i < c; i++)         cout << endl;
    {     }
        if (k == n || p ==1) }
        {
            return;
        }
        a[k] = i;
        int m = 0;
        for (int j = 0; j < gp[k].size();
Input:-
j++)
        {
            if ( gp[k][j] == 1)
            {if(a[j]==i){
                m = 1;
                break;}
            }
Output:-
        }
        if (m == 1 && i == c - 1)
        {
            p = 1;
        }
        if (m == 0)
        {
            k++;
            m_color(a,gp, n, c, p, k);
        } Analysis:
The time complexity is 0(c^n) or 0(m^n) is then the current element can be
and space complexity is 0(n). taken as a part of subset and we
make a call for the next element. To
see whether it is also a part of it or
Task:-Subset Sum not.
● If the sum of previous sum and
Problem current element is equal to m then
we print the solution.
Subset sum problem is to find subset ● And if both the conditions are not
true then we backtrack and make
of elements that are selected from a
that element again 0 and move to
given set whose sum adds up to a next element skipping it.
given number K. We are considering ● Eg. n(number of elements)=6
the set contains non-negative values. ,m(sum)=30 & the array
It is assumed that the input set is a={5,10,12,13,15,18}
unique (no duplicates are presented).

Procedure:
● Take the input array consisting of n
distinct numbers and value of m
(required sum).
● Taken an array X of the size equal to
the size of weight array and initialise
all its elements to 0.
● Pass weight array, X array, m, initial Algorithm:-
sum (0), stage (initial 0) and total
sum of elements to the seq( a[],vector<set<int>>&b, n, x,i,
sum_of_subsets function. sum,set<int>s){

● We start with considering the first


element to be part of subset. if(sum==x)
then

● Then we generate the left sub tree. s.clear


We see whether the sum of previous return
sum ,current element and one next
element is less than equal to m if it
else if(sum>x)     int sum=0;
    set<int>s;
then     seq(a,b,n,x,0,sum,s);
    cout<<" total number of possible
s.clear subsets with desired sum are
"<<b.size()<<endl;
return;     for(int i=0;i<b.size();i++){
        set<int>::iterator it;
       
for(it=b[i].begin();it!=b[i].end();it++){
else if(i<n)             cout<<*it<<" ";
        }
then    cout<<endl;
    }
seq(a,b,n,x,i+1,sum,s);  
}
s.insert(a[i]);
seq(a,b,n,x,i+1,sum+a[i],s);
Input/Output:-
}

Code:
#include<bits/stdc++.h>
using namespace std;
void seq(int a[],vector<set<int>>&b,int
n,int x,int i,int sum,set<int>s){
   
    if(sum==x){
b.push_back(s);
return;
    } Analysis:
    else if(sum>x){
        s.clear(); The time complexity of this method is
        return; 0(2^n) . backtracking method to solve this
    }
    else if(i<n){
is a bit faster than the recursive approach
           seq(a,b,n,x,i+1,sum,s); which too takes the exponential time for
        s.insert(a[i]); the execution.
        seq(a,b,n,x,i+1,sum+a[i],s);

     
    }
}
int main(){
    int n,x;
    cin>>n>>x;
    int a[n];
    for(int i=0;i<n;i++){
        cin>>a[i];
    }
    vector<set<int>>b;
● Step 2 is repeated until the table is
Task:-Longest Common filled.
Subsequence(LCS) ● Longest Common Subsequence fill
all the values
Problem ● Fill all the values
● The value in the last row and the
LCS Problem Statement: Given two last column is the length of the
sequences, find the length of longest longest common subsequence.
subsequence present in both of them.  ● Longest Common Subsequence
 A subsequence is a sequence that appears length
● The bottom right corner is the
in the same relative order, but not
length of the LCS
necessarily contiguous. For example, “abc”,
● In order to find the longest common
“abg”, “bdf”, “aeg”, ”acefg”, .. etc are
subsequence, start from the last
subsequences of “abcdefg”. 
element and follow the direction of
Procedure: the arrow. The elements
corresponding to () symbol form the
● Create a table of dimension longest common subsequence.
n+1*m+1 where n and m are the
lengths of X and Y respectively. The Algorithm:-
first row and the first column are
filled with zeros. lcs( s1, s2, i, j, vector<string> &a, s){
● Initialise a table
● Fill each cell of the table using the
following logic. if (i == s1.length() || j == s2.length())
● If the character correspoding to the then
current row and current column are
matching, then fill the current cell by a.push_back(s);
adding one to the diagonal element. s.clear();
Point an arrow to the diagonal cell.
● Else take the maximum value from
the previous column and previous return;
row element for filling the current
cell. Point an arrow to the cell with
maximum value. If they are equal, else if (s1[i] == s2[j])
point to any of them.
then
● Longest Common Subsequence fill
the values { s+=s1[i];
● Fill the values
lcs(s1, s2, i + 1, j + 1, a, s);     for (int i = 0; i < a.size(); i++)
    {
}         int x = ma;
        int b = a[i].size();
else         ma = max(x, b);
    }
then     cout<<"length of lcs is "<<ma<<endl;
    int k=0;
{ lcs(s1, s2, i + 1, j, a, s)     for (int i = 0; i < a.size(); i++)
    {
lcs(s1, s2, i, j + 1, a, s);         if (a[i].length() == ma)
        {k++;
}             cout << a[i] << endl;
        }
}     }
    cout<<"count of lcs is "<<k<<endl;
}
Code:
#include <bits/stdc++.h>
using namespace std;
void lcs(string s1, string s2, int i, int Input/Output:-
j, vector<string> &a, string s){
   
    if (i == s1.length() || j ==
s2.length())
    {
        a.push_back(s);
        s.clear();
   
        return;
    }
    else if (s1[i] == s2[j])
    {
        Explanation:-
      s+=s1[i];
     
        lcs(s1, s2, i + 1, j + 1, a, s);
    }
    else
    {
       
        lcs(s1, s2, i + 1, j, a, s);
     
        lcs(s1, s2, i, j + 1, a, s);
    }
}
int main()
{
    string s1, s2; Learnings:-
    cin >> s1 >> s2;
    vector<string> a; From this experiment we learnt how to use
    string s; backtracking algorithm.In Lcs problem we
    int ma = INT16_MIN;
    lcs(s1, s2, 0, 0, a, s);
found the longest common subsequence
that can exist using the concept of
backtracking. Time complexity of this
isO(n*m) where n and m are the lengths of
the strings.

You might also like