Program 3

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 13

Program 3

AIM: a. Obtain the Topological ordering of vertices in a given digraph.

#include <stdio.h>
#include <stdlib.h>

#define MAX_VERTICES 100

struct Graph {
int V;
int** adjacency_matrix;
};

struct Graph* createGraph(int V) {


struct Graph* graph = (struct Graph*)malloc(sizeof(struct Graph));
graph->V = V;

// Allocate memory for the adjacency matrix


graph->adjacency_matrix = (int**)malloc(V * sizeof(int*));
for (int i = 0; i < V; i++) {
graph->adjacency_matrix[i] = (int*)malloc(V * sizeof(int));
}

// Initialize the adjacency matrix


for (int i = 0; i < V; i++) {
for (int j = 0; j < V; j++) {
graph->adjacency_matrix[i][j] = 0;
}
}

return graph;
}

void addEdge(struct Graph* graph, int src, int dest) {


graph->adjacency_matrix[src][dest] = 1;
}

void DFS(struct Graph* graph, int v, int* visited, int* topological_order, int* index) {
visited[v] = 1;

for (int i = 0; i < graph->V; i++) {


if (graph->adjacency_matrix[v][i] == 1 && !visited[i]) {
DFS(graph, i, visited, topological_order, index);
}
}

topological_order[(*index)--] = v;
}

void topologicalSort(struct Graph* graph) {

5CS4-23: Analysis of Algorithms


int V = graph->V;
int* visited = (int*)malloc(V * sizeof(int));
int* topological_order = (int*)malloc(V * sizeof(int));
int index = V - 1;

for (int i = 0; i < V; i++) {


visited[i] = 0;
}

for (int i = 0; i < V; i++) {


if (!visited[i]) {
DFS(graph, i, visited, topological_order, &index);
}
}

printf("Topological Ordering: ");


for (int i = 0; i < V; i++) {
printf("%d ", topological_order[i]);
}
printf("\n");

free(visited);
free(topological_order);
}

int main() {
int V, E;
printf("Enter the number of vertices: ");
scanf("%d", &V);

struct Graph* graph = createGraph(V);

printf("Enter the number of edges: ");


scanf("%d", &E);

for (int i = 0; i < E; i++) {


int src, dest;
printf("Enter edge %d (source destination): ", i + 1);
scanf("%d %d", &src, &dest);
addEdge(graph, src, dest);
}

printf("Topological Sort Result:\n");


topologicalSort(graph);

return 0;
}

Output:

5CS4-23: Analysis of Algorithms


Enter the number of vertices: 5
Enter the number of edges: 4
Enter edge 1 (source destination): 1
3
Enter edge 2 (source destination): 2
4
Enter edge 3 (source destination): 3
5
Enter edge 4 (source destination): 4
2
Topological Sort Result:
Topological Ordering: 2 4 1 3 0

5CS4-23: Analysis of Algorithms


Viva Questions

Q1: What is a digraph? And what is the concept of topological ordering of vertices in a
digraph?
Ans: A digraph, or directed graph, is a graph in which edges have a specific direction,
indicating a one-way relationship between vertices.
A topological ordering is a linear ordering of the vertices in a digraph such that for every
directed edge (u, v), vertex u comes before vertex v in the ordering.

Q2: How can you obtain a topological ordering of vertices in a digraph?


Ans: One common algorithm to obtain a topological ordering is the Depth-First Search
(DFS) based approach, where vertices are visited recursively and added to the ordering after
all their adjacent vertices have been visited.

Q3: Is a topological ordering unique for a given digraph?


Ans: No, a digraph can have multiple valid topological orderings. The ordering depends on
the specific ordering of vertices during the DFS traversal.

Q4: What is the key property that a digraph must satisfy for a topological ordering to
exist?
Ans: A digraph must be a Directed Acyclic Graph (DAG) for a valid topological ordering to
exist. Cycles in the graph would create contradictions in the ordering.

Q5: What is the time complexity of obtaining a topological ordering using depth-first
search?
Ans: The time complexity is O(V + E), where V is the number of vertices and E is the
number of edges in the graph.

5CS4-23: Analysis of Algorithms


b. Compute the transitive closure of a given directed graph using Warshall's algorithm.

#include <stdio.h>
#include <stdlib.h>

#define MAX_VERTICES 100

void transitiveClosure(int V, int graph[MAX_VERTICES][MAX_VERTICES]) {


int closure[MAX_VERTICES][MAX_VERTICES];

// Initialize the closure matrix with the input graph


for (int i = 0; i < V; i++) {
for (int j = 0; j < V; j++) {
closure[i][j] = graph[i][j];
}
}

// Compute transitive closure using Warshall's algorithm


for (int k = 0; k < V; k++) {
for (int i = 0; i < V; i++) {
for (int j = 0; j < V; j++) {
closure[i][j] = closure[i][j] || (closure[i][k] && closure[k][j]);
}
}
}

// Print the transitive closure matrix


printf("Transitive Closure Matrix:\n");
for (int i = 0; i < V; i++) {
for (int j = 0; j < V; j++) {
printf("%d ", closure[i][j]);
}
printf("\n");
}
}

int main() {
int V;
printf("Enter the number of vertices: ");
scanf("%d", &V);

int graph[MAX_VERTICES][MAX_VERTICES];

printf("Enter the adjacency matrix:\n");


for (int i = 0; i < V; i++) {
for (int j = 0; j < V; j++) {
scanf("%d", &graph[i][j]);
}

5CS4-23: Analysis of Algorithms


}

transitiveClosure(V, graph);

return 0;
}

Output:

Enter the number of vertices: 3


Enter the adjacency matrix:
1
2
4
7
5
6
9
3
12
11
Transitive Closure Matrix:
111
111
111

5CS4-23: Analysis of Algorithms


Viva Questions

Q1: What is the transitive closure of a directed graph?


Ans: The transitive closure of a directed graph is a matrix that represents the reachability of
all pairs of vertices in the graph. It indicates whether there is a path between every pair of
vertices.

Q2: Explain Warshall's algorithm briefly.


Ans: Warshall's algorithm is used to compute the transitive closure of a graph. It iteratively
updates the transitive closure matrix by considering all possible intermediate vertices to
determine if a path exists between two vertices.

Q3: How does Warshall's algorithm represent the graph and its transitive closure?
Ans: Warshall's algorithm uses an adjacency matrix to represent the graph and updates a
separate matrix to represent the transitive closure.

Q4: What is the time complexity of Warshall's algorithm?


Ans: The time complexity of Warshall's algorithm is O(V^3), where V is the number of
vertices in the graph.

Q5: Can Warshall's algorithm be applied to a weighted graph?


Ans: Warshall's algorithm is designed for unweighted graphs. It doesn't take edge weights
into account; it only determines reachability.

5CS4-23: Analysis of Algorithms


Program 4
AIM: Implement 0/1 Knapsack problem using Dynamic Programming.

#include <stdio.h>

#define MAX_ITEMS 100

// Structure to represent an item


struct Item {
int weight;
int value;
};

// Function to calculate the maximum of two integers


int max(int a, int b) {
return (a > b) ? a : b;
}

// Function to solve the 0/1 Knapsack problem using dynamic programming


int knapsack(int capacity, struct Item items[], int n) {
int dp[MAX_ITEMS + 1][capacity + 1];

// Initialize the dp table


for (int i = 0; i <= n; i++) {
for (int w = 0; w <= capacity; w++) {
if (i == 0 || w == 0) {
dp[i][w] = 0;
} else if (items[i - 1].weight <= w) {
dp[i][w] = max(items[i - 1].value + dp[i - 1][w - items[i - 1].weight], dp[i - 1][w]);
} else {
dp[i][w] = dp[i - 1][w];
}
}
}

return dp[n][capacity];
}

int main() {
int n, capacity;

printf("Enter the number of items: ");


scanf("%d", &n);

struct Item items[MAX_ITEMS];

printf("Enter the weight and value of each item:\n");


for (int i = 0; i < n; i++) {
printf("Item %d (weight value): ", i + 1);

5CS4-23: Analysis of Algorithms


scanf("%d %d", &items[i].weight, &items[i].value);
}

printf("Enter the knapsack capacity: ");


scanf("%d", &capacity);

int max_value = knapsack(capacity, items, n);

printf("Maximum value in the knapsack: %d\n", max_value);

return 0;
}

Output:

Enter the number of items: 5


Enter the weight and value of each item:
Item 1 (weight value): 10 12
Item 2 (weight value): 8 7
Item 3 (weight value): 11 9
Item 4 (weight value): 9 8
Item 5 (weight value): 12 10
Enter the knapsack capacity: 50
Maximum value in the knapsack: 46

5CS4-23: Analysis of Algorithms


Viva Questions
Q1: What is the 0/1 Knapsack problem?
Ans: The 0/1 Knapsack problem is a combinatorial optimization problem where you have a
set of items, each with a weight and a value, and you want to select a subset of items to
maximize the total value while not exceeding a given capacity.

Q2: What is Dynamic Programming?


Ans: Dynamic Programming is a technique used to solve complex problems by breaking
them down into smaller subproblems and storing the solutions to these subproblems to avoid
redundant calculations.

Q3: How does Dynamic Programming solve the 0/1 Knapsack problem efficiently?
Ans: Dynamic Programming solves the problem by building a table where each cell
represents the maximum value that can be obtained with a certain weight capacity and a
subset of items. The values are computed iteratively based on previously calculated
subproblems.

Q4: What does dp[i][w] represent in the DP table?


Ans: dp[i][w] represents the maximum value that can be obtained by considering the first 'i'
items and having a weight capacity of 'w'.

Q5: What is the advantage of using Dynamic Programming for the 0/1 Knapsack
problem?
Ans: Dynamic Programming avoids redundant calculations by storing intermediate results,
leading to significant efficiency improvements compared to naive recursive approaches.

5CS4-23: Analysis of Algorithms


Program 10
AIM: Implement N Queen's problem using Back Tracking.
#include <stdio.h>
#include <stdbool.h>

#define N 8 // Define the board size (change this value to solve for different N)

// Function to print the chessboard


void printBoard(int board[N][N]) {
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
printf("%c ", board[i][j] ? 'Q' : '.');
}
printf("\n");
}
}

// Function to check if it's safe to place a queen at board[row][col]


bool isSafe(int board[N][N], int row, int col) {
int i, j;

// Check the left side of this row


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

// Check upper diagonal on the left side


for (i = row, j = col; i >= 0 && j >= 0; i--, j--) {
if (board[i][j]) {
return false;
}
}

// Check lower diagonal on the left side


for (i = row, j = col; i < N && j >= 0; i++, j--) {
if (board[i][j]) {
return false;
}
}

return true;
}

// Recursive function to solve N-Queens problem using backtracking


bool solveNQueens(int board[N][N], int col) {
if (col >= N) {
return true; // All queens are placed successfully
}

5CS4-23: Analysis of Algorithms


for (int i = 0; i < N; i++) {
if (isSafe(board, i, col)) {
board[i][col] = 1; // Place the queen at board[i][col]

// Recur to place the rest of the queens


if (solveNQueens(board, col + 1)) {
return true;
}

// If placing queen at board[i][col] doesn't lead to a solution, then backtrack


board[i][col] = 0;
}
}

return false; // Queen can't be placed in any row in this column


}

int main() {
int board[N][N];

// Initialize the chessboard


for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
board[i][j] = 0;
}
}

if (solveNQueens(board, 0)) {
printf("Solution found:\n");
printBoard(board);
} else {
printf("No solution exists.\n");
}

return 0;
}

Output:

Solution found:
Q.......
......Q.
....Q...
.......Q
.Q......
...Q....
.....Q..
..Q.....
Viva Questions

5CS4-23: Analysis of Algorithms


Q1: What is the N-Queens problem?
Ans: The N-Queens problem is a classic combinatorial puzzle that involves placing N chess
queens on an N×N chessboard in such a way that no two queens threaten each other.

Q2: What is backtracking?


Ans: Backtracking is a general algorithmic technique that involves systematically searching
for a solution to a problem by exploring possible options and undoing choices that do not lead
to a valid solution.

Q3: What is the base case in the N-Queens backtracking algorithm?


Ans: The base case is reached when all N queens are successfully placed on the board
without conflicts, and a valid solution is found.

Q4: What is the time complexity of the N-Queens backtracking algorithm?


Ans: The time complexity of the algorithm depends on the specific implementation, but it is
typically exponential, O(N!), due to the large number of possible board configurations.

Q5: How do you represent the chessboard in code for the N-Queens problem?
Ans: The chessboard can be represented using a 2D array where each cell represents a
square on the board, and the presence of a queen is indicated by a specific value.

5CS4-23: Analysis of Algorithms

You might also like