0% found this document useful (0 votes)
18 views

Assignment_2

This document is a digital assignment submitted by Raghav Kohli for a Design and Analysis of Algorithms course, detailing various algorithm implementations. It includes solutions for the N-Queens problem, Matrix Chain Multiplication, Longest Common Subsequence, 0-1 Knapsack, Assembly Line Scheduling, and Job Sequencing Problem using branch and bound. Each section provides an approach, code implementation, and test cases to validate the algorithms.

Uploaded by

Raghav Kohli
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
18 views

Assignment_2

This document is a digital assignment submitted by Raghav Kohli for a Design and Analysis of Algorithms course, detailing various algorithm implementations. It includes solutions for the N-Queens problem, Matrix Chain Multiplication, Longest Common Subsequence, 0-1 Knapsack, Assembly Line Scheduling, and Job Sequencing Problem using branch and bound. Each section provides an approach, code implementation, and test cases to validate the algorithms.

Uploaded by

Raghav Kohli
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 26

Design and Analysis of Algorithm DIGITAL

ASSIGNMENT

Submitted by

Raghav Kohli
Reg.no: 23BCI0219
Branch: Bachelor of Technology in Computer Science and Engineering(With specialization)
School: SCOPE

Under the guidance of

Prof. Shalini L

VIT, Vellore
DAA Lab assignment 2
(Note: The questions are not in the order of the question sheet)
Q1. Write a program to implement N-Queens problem

Approach:

Use backtracking to place queens one by one in each row, ensuring no two attack each other. If a valid position is
found, recursively place the next queen; otherwise, backtrack and try the next possibility.

Code:

#include <iostream>

#include <vector>
using namespace std;

void printBoard(vector<vector<int>> &board, int N)


{
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j++)
{
cout << (board[i][j] ? "Q " : "- ");
}
cout << endl;
}
cout << endl;
}

bool isSafe(vector<vector<int>> &board, int row, int col, int N)


{
for (int i = 0; i < col; i++)
{
if (board[row][i])
return false;
}

for (int i = row, j = col; i >= 0 && j >= 0; i--, j--)


{
if (board[i][j])
return false;
}

for (int i = row, j = col; i < N && j >= 0; i++, j--)


{
if (board[i][j])
return false;
}

return true;
}

int countSolutions = 0;
bool solveNQueens(vector<vector<int>> &board, int col, int N)
{
if (col >= N)
{
countSolutions++;
printBoard(board, N);
return true;
}

bool res = false;


for (int i = 0; i < N; i++)
{
if (isSafe(board, i, col, N))
{
board[i][col] = 1;
res = solveNQueens(board, col + 1, N) || res;
board[i][col] = 0;
}
}

return res;
}

int main()
{
int N;
cout << "Enter the number of queens: ";
cin >> N;

vector<vector<int>> board(N, vector<int>(N, 0));

solveNQueens(board, 0, N);

cout << "Total solutions: " << countSolutions << endl;

return 0;
}
Pseudocode:
Output:

Test case 01:

Test Case 02:


Test Case 03:
Q3- (ii): Matrix Chain Multiplication

Approach:

Use Dynamic Programming (DP) with Memoization to find the optimal way to parenthesize matrices to minimize
multiplication cost. Define dp[i][j] as the minimum cost to multiply matrices from index i to j, and compute it using
the recurrence:
Code:

#include <iostream>
#include <vector>
#include <limits.h>

using namespace std;

int matrixChainOrder(vector<int> &p, int n)


{
vector<vector<int>> dp(n, vector<int>(n, 0));

for (int len = 2; len < n; len++)


{
for (int i = 1; i < n - len + 1; i++)
{
int j = i + len - 1;
dp[i][j] = INT_MAX;
for (int k = i; k < j; k++)
{
int cost = dp[i][k] + dp[k + 1][j] + p[i - 1] * p[k] * p[j];
dp[i][j] = min(dp[i][j], cost);
}
}
}
return dp[1][n - 1];
}

int main()
{
int n;
cout << "Enter number of matrices: ";
cin >> n;
vector<int> p(n + 1);

cout << "Enter the dimensions: ";


for (int i = 0; i <= n; i++)
{
cin >> p[i];
}

cout << "Minimum multiplication cost: " << matrixChainOrder(p, n + 1) << endl;

return 0;
}
Pseudocode:
Output:

Test case 1 – Normal case

Test case 2- If all the matrices have same dimensions


Q3- (iii) Longest Common Subsequence

Approach:

Use Dynamic Programming (DP) with a 2D table to compute the Longest Common Subsequence (LCS) length. Define
dp[i][j] as the length of the LCS of prefixes X[0...i-1] and Y[0...j-1], using the recurrence:

Code:

#include <iostream>
#include <vector>

using namespace std;

string lcs(string X, string Y)


{
int m = X.length(), n = Y.length();
vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));

// Fill the DP table


for (int i = 1; i <= m; i++)
{
for (int j = 1; j <= n; j++)
{
if (X[i - 1] == Y[j - 1])
dp[i][j] = dp[i - 1][j - 1] + 1;
else
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
}
}

// Reconstruct the LCS string


int index = dp[m][n];
string lcsStr(index, ' ');
int i = m, j = n;

while (i > 0 && j > 0)


{
if (X[i - 1] == Y[j - 1])
{
lcsStr[--index] = X[i - 1];
i--;
j--;
}
else if (dp[i - 1][j] > dp[i][j - 1])
{
i--;
}
else
{
j--;
}
}

return lcsStr;
}

int main()
{
string X, Y;
cout << "Enter first string: ";
cin >> X;
cout << "Enter second string: ";
cin >> Y;

string result = lcs(X, Y);


cout << "Length of LCS: " << result.length() << endl;
cout << "LCS: " << result << endl;
return 0;
}

Pseudocode:
Output:
Test case 01- Normal case

Test case 2- No common subsequence

Test case -03 Entire string is LCS


Test case 04- Multiple common substring – Lexicographically first

Q3-(iv): 0-1 knapsack

Approach:

Use Dynamic Programming (DP) with a 2D table to solve the 0/1 Knapsack Problem. Define dp[i][w] as the
maximum value that can be obtained using the first i items with a weight limit w, using the recurrence:

Code:

#include <iostream>
#include <vector>

using namespace std;

int knapsack(int W, vector<int> &weights, vector<int> &values, int n)


{
vector<vector<int>> dp(n + 1, vector<int>(W + 1, 0));

for (int i = 1; i <= n; i++)


{
for (int w = 1; w <= W; w++)
{
if (weights[i - 1] <= w)
dp[i][w] = max(values[i - 1] + dp[i - 1][w - weights[i - 1]], dp[i
- 1][w]);
else
dp[i][w] = dp[i - 1][w];
}
}
return dp[n][W];
}

int main()
{
int n, W;
cout << "Enter number of items: ";
cin >> n;
vector<int> values(n), weights(n);

cout << "Enter weights and values: ";


for (int i = 0; i < n; i++)
{
cin >> weights[i] >> values[i];
}

cout << "Enter knapsack capacity: ";


cin >> W;

cout << "Maximum value in knapsack: " << knapsack(W, weights, values, n) <<
endl;
return 0;
}

Pseudocode:
Output:

Test case 01- general case

Test Case 02- Exact fit


Test Case 03- Single item fits

Test case 04: All items too heavy

Test case 05- Zero knapsack capacity


Q3-(i): ALS (Assembly Line Scheduling)

Approach:

Use Dynamic Programming (DP) with two arrays to compute the minimum time to assemble a product. Define
T1[i] and T2[i] as the minimum time to reach station i on line 1 and line 2, respectively. Use the recurrence:

where a1[i] and a2[i] are processing times, and t1[i-1], t2[i-1] are transfer times. Compute results
iteratively and return min(T1[n-1] + x1, T2[n-1] + x2), where x1 and x2 are exit times.

Code:

Code:
#include <bits/stdc++.h>

using namespace std;

int min(int a, int b)


{
return a < b ? a : b;
}

int ALS(vector<vector<int>> &a, vector<vector<int>> &t, vector<int> &e,


vector<int> &x, int num_stations)
{
vector<int> T1(num_stations), T2(num_stations);

T1[0] = e[0] + a[0][0];


T2[0] = e[1] + a[1][0];

for (int i = 1; i < num_stations; ++i)


{
T1[i] = min(T1[i - 1] + a[0][i], T2[i - 1] + t[1][i - 1] + a[0][i]);
T2[i] = min(T2[i - 1] + a[1][i], T1[i - 1] + t[0][i - 1] + a[1][i]);
}

return min(T1[num_stations - 1] + x[0], T2[num_stations - 1] + x[1]);


}

int main()
{
int num_stations;
cout << "Enter the number of stations: ";
cin >> num_stations;

vector<vector<int>> a(2, vector<int>(num_stations));


vector<vector<int>> t(2, vector<int>(num_stations - 1));
vector<int> e(2), x(2);

cout << "Enter processing times for line 1: ";


for (int i = 0; i < num_stations; i++)
cin >> a[0][i];

cout << "Enter processing times for line 2: ";


for (int i = 0; i < num_stations; i++)
cin >> a[1][i];

cout << "Enter transfer times from line 1 to line 2: ";


for (int i = 0; i < num_stations - 1; i++)
cin >> t[0][i];

cout << "Enter transfer times from line 2 to line 1: ";


for (int i = 0; i < num_stations - 1; i++)
cin >> t[1][i];

cout << "Enter entry times for both lines: ";


cin >> e[0] >> e[1];

cout << "Enter exit times for both lines: ";


cin >> x[0] >> x[1];

cout << "Minimum time to leave the assembly line: " << ALS(a, t, e, x,
num_stations) << endl;

return 0;
}
Pseudocode:
Output:
Test Case 01- Normal Case:

Test Case 02:

Q2. Job sequencing Problem using branch and bound.

Approach:

The Job Sequencing Problem using Branch and Bound (B&B) aims to minimize penalties by optimally scheduling jobs
within their deadlines. The approach is:

1. Sort Jobs in decreasing order of penalty.

2. Use a Priority Queue (Min-Heap) to explore solutions, where each node represents a partial job schedule.

3. At each step, either include a job in the sequence (if a slot is available) or exclude it (adding its penalty).

4. Branch to explore both possibilities and use Bounding to prune non-optimal solutions.

5. The minimum penalty is obtained when all jobs are processed optimally.
Code:

#include <iostream>

#include <vector>
#include <queue>
#include <algorithm>
#include <climits>

using namespace std;

struct Job
{
int id;
int penalty;
int deadline;
};

struct Node
{
vector<bool> assigned;
int level;
int penalty;
};

// Comparison function for priority queue (min-heap based on penalty)


struct Compare
{
bool operator()(const Node &a, const Node &b)
{
return a.penalty > b.penalty;
}
};

int jobSequencing(vector<Job> &jobs, int maxDeadline)


{
sort(jobs.begin(), jobs.end(), [](const Job &a, const Job &b)
{ return a.penalty > b.penalty; });

priority_queue<Node, vector<Node>, Compare> pq;


Node root;
root.assigned = vector<bool>(maxDeadline, false);
root.level = 0;
root.penalty = 0;
pq.push(root);
int minPenalty = INT_MAX;

while (!pq.empty())
{
Node current = pq.top();
pq.pop();

if (current.level == jobs.size())
{
minPenalty = min(minPenalty, current.penalty);
continue;
}

int jobIndex = current.level;

// Option 1: Include the job if possible


for (int d = min(jobs[jobIndex].deadline, maxDeadline) - 1; d >= 0; --
d)
{
if (!current.assigned[d])
{
Node include = current;
include.level++;
include.assigned[d] = true;
pq.push(include);
break;
}
}

// Option 2: Exclude the job and add penalty


Node exclude = current;
exclude.level++;
exclude.penalty += jobs[jobIndex].penalty;
pq.push(exclude);
}

return minPenalty;
}

int main()
{
int N;
cout << "Enter number of jobs: ";
cin >> N;

vector<Job> jobs(N);
cout << "Enter penalty and deadline for each job: " << endl;
int maxDeadline = 0;
for (int i = 0; i < N; ++i)
{
jobs[i].id = i + 1;
cin >> jobs[i].penalty >> jobs[i].deadline;
maxDeadline = max(maxDeadline, jobs[i].deadline);
}

cout << "Min Penalty: " << jobSequencing(jobs, maxDeadline) << endl;

return 0;
}

Pseudocode:
Output:

Test Case 1:

Test Case 02:


Test case 03

End of Assignment

You might also like