Professional Documents
Culture Documents
PANJAB UNIVERSITY, SECTOR 25, CHANDIGARH
LAB REPORT
CSE DEPARTMENT
BATCH : 2020-24
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 */
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++
/* 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:-
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]
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.
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;
}
}
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 :
}
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.
vector<set<int>> s(n);
for (int i = 0; i < n; i++)
s[i].insert(i);
int mincost = 0;
vector<pair<int, int>> MST;
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;
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++;
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:
● 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){
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.