Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 14

BACKTRACKING

Subset Sum problem

Subset sum problem is to find subset of elements that are selected from a given set whose sum adds up to a given number K. We are considering the set
contains non-negative values. It is assumed that the input set is unique (no duplicates are presented).

Algorithm for sum of subset


Algorithm SUB_SET_PROBLEM, (i,sum, W, remSum)
// Description: Solve sub of subset problem using backtracking

//Input: W: Number for which subset is to be computed

i: Item index
sum: Sum of integers selected so far
remSum: Size of remaining problem i.e. (W - sum)
// Output: Solution tuple X

if FEASIBLE SUB_SET() == 1 then


if (sum == W) then
print X [1...i]
end
elseX [i + 1] <- 1
SUB SET PROBLEM(i +1. sum + w[i] + 1 ,W, remSum - w * [i] + 1 )
X[i+1] <- 0 //Exclude the " item
SUB_SET_PROBLEM( i + 1, sum, W, remSum- w[i] + 1 )
end
Function FEASIBLE_SUB_SET()

if (sum+remSum≥ W) AND (sum == W )


or ( sum + w[i] + 1 <= W) then
return 0
end

return 1

CODE:

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

#define ARRAYSIZE(a) (sizeof(a))/(sizeof(a[0]))

static int total_nodes;

// prints subset found


void printSubset(int A[], int size)
{
for(int i = 0; i < size; i++)
{
printf("%*d", 5, A[i]);
}

printf("\n");
}

// qsort compare function


int comparator(const void *pLhs, const void *pRhs)
{
int *lhs = (int *)pLhs;
int *rhs = (int *)pRhs;

return *lhs > *rhs;


}

// inputs
// s - set vector
// t - tuplet vector
// s_size - set size
// t_size - tuplet size so far
// sum - sum so far
// ite - nodes count
// target_sum - sum to be found
void subset_sum(int s[], int t[], int s_size, int t_size, int sum, int ite, int const target_sum)
{
total_nodes++;

if( target_sum == sum )


{
// We found sum
printSubset(t, t_size);
// constraint check
if( ite + 1 < s_size && sum - s[ite] + s[ite+1] <= target_sum )
{
// Exclude previous added item and consider next candidate
subset_sum(s, t, s_size, t_size-1, sum - s[ite], ite + 1, target_sum);
}
return;
}
else
{
// constraint check
if( ite < s_size && sum + s[ite] <= target_sum )
{
// generate nodes along the breadth
for( int i = ite; i < s_size; i++ )
{
t[t_size] = s[i];

if( sum + s[i] <= target_sum )


{
// consider next level node (along depth)
subset_sum(s, t, s_size, t_size + 1, sum + s[i], i + 1, target_sum);
}
}
}
}
}

// Wrapper that prints subsets that sum to target_sum


void generateSubsets(int s[], int size, int target_sum)
{
int *tuplet_vector = (int *)malloc(size * sizeof(int));

int total = 0;

// sort the set


qsort(s, size, sizeof(int), &comparator);

for( int i = 0; i < size; i++ )


{
total += s[i];
}

if( s[0] <= target_sum && total >= target_sum )


{

subset_sum(s, tuplet_vector, size, 0, 0, 0, target_sum);

free(tuplet_vector);
}

int main()
{
int weights[] = {15, 22, 14, 26, 32, 9, 16, 8};
int target = 53;

int size = ARRAYSIZE(weights);

generateSubsets(weights, size, target);

printf("Nodes generated %d\n", total_nodes);

return 0;
}

Graph Coloring Problem

Input:   graph = {0, 1, 1, 1},


                          {1, 0, 1, 0},
                          {1, 1, 0, 1},
                          {1, 0, 1, 0}
Output:  Solution Exists: Following are the assigned colors: 1  2   3   2
Explanation:  By coloring the vertices with following colors, adjacent  vertices does not have same colors

CODE:

// C program for solution of M


// Coloring problem using backtracking
  
#include <stdbool.h>
#include <stdio.h>
  
// Number of vertices in the graph
#define V 4
  
void printSolution(int color[]);
  
/* A utility function to check if the current color assignment is safe for vertex v i.e. checks whether the edge exists or
not (i.e, graph[v][i]==1). If exist then checks whether the color to be filled in the new vertex(c is sent in the parameter)
is already used by its adjacent vertices(i-->adj vertices) or not (i.e, color[i]==c) */

bool isSafe(int v, bool graph[V][V], int color[], int c)


{
    for (int i = 0; i < V; i++)
        if (graph[v][i] && c == color[i])
            return false;
    return true;
}
  
/* A recursive utility function to solve m coloring problem */
bool graphColoringUtil(bool graph[V][V], int m, int color[],
                       int v)
{
    /* base case: If all vertices are assigned a color then return true */
    if (v == V)
        return true;
  
    /* Consider this vertex v and try different colors */
    for (int c = 1; c <= m; c++) {
        /* Check if assignment of color c to v is fine*/
        if (isSafe(v, graph, color, c)) {
            color[v] = c;
  
            /* recur to assign colors to rest of the vertices */
            if (graphColoringUtil(graph, m, color, v + 1)
                == true)
                return true;
  
            /* If assigning color c doesn't lead to a solution then remove it */
            color[v] = 0;
        }
    }
  
    /* If no color can be assigned to this vertex then return false */
    return false;
}
  
/* This function solves the m Coloring problem using Backtracking. It mainly
   uses graphColoringUtil() to solve the problem. It returns false if the m colors cannot be assigned, otherwise return true
and prints assignments of colors to all vertices. Please note that there may be more than one solutions, this function
prints one of the feasible solutions.*/
bool graphColoring(bool graph[V][V], int m)
{
    // Initialize all color values as 0.
    // This initialization is needed
    // correct functioning of isSafe()
    int color[V];
    for (int i = 0; i < V; i++)
        color[i] = 0;
  
    // Call graphColoringUtil() for vertex 0
    if (graphColoringUtil(graph, m, color, 0) == false) {
        printf("Solution does not exist");
        return false;
    }
  
    // Print the solution
    printSolution(color);
    return true;
}
  
/* A utility function to print solution */
void printSolution(int color[])
{
    printf("Solution Exists:"
           " Following are the assigned colors \n");
    for (int i = 0; i < V; i++)
        printf(" %d ", color[i]);
    printf("\n");
}
  
// Driver code
int main()
{
    /* Create following graph and test
       whether it is 3 colorable
      (3)---(2)
       |   / |
       |  /  |
       | /   |
      (0)---(1)
    */
    bool graph[V][V] = {
        { 0, 1, 1, 1 },
        { 1, 0, 1, 0 },
        { 1, 1, 0, 1 },
        { 1, 0, 1, 0 },
    };
    int m = 3; // Number of colors
  
    // Function call
    graphColoring(graph, m);
    return 0;
}

OUTPUT:

Solution Exists: Following are the assigned colors

1 2 3 2

Hamiltonian Cycle

NAÏVE ALGORITHM:
while there are untried configuration
{
generate the next configuration
if ( there are edges between two consecutive vertices of this
configuration and there is an edge from the last vertex to
the first ).
{
print this configuration;
break;
}
}

CODE:
/* C program for solution of Hamiltonian Cycle problem
   using backtracking */
#include<stdio.h>
 
// Number of vertices in the graph
#define V 5
 
void printSolution(int path[]);
 
/* A utility function to check if the vertex v can be added at
   index 'pos' in the Hamiltonian Cycle constructed so far (stored
   in 'path[]') */
bool isSafe(int v, bool graph[V][V], int path[], int pos)
{
    /* Check if this vertex is an adjacent vertex of the previously
       added vertex. */
    if (graph [ path[pos-1] ][ v ] == 0)
        return false;
 
    /* Check if the vertex has already been included.
      This step can be optimized by creating an array of size V */
    for (int i = 0; i < pos; i++)
        if (path[i] == v)
            return false;
 
    return true;
}
 
/* A recursive utility function to solve hamiltonian cycle problem */
bool hamCycleUtil(bool graph[V][V], int path[], int pos)
{
    /* base case: If all vertices are included in Hamiltonian Cycle */
    if (pos == V)
    {
        // And if there is an edge from the last included vertex to the
        // first vertex
        if ( graph[ path[pos-1] ][ path[0] ] == 1 )
           return true;
        else
          return false;
    }
 
    // Try different vertices as a next candidate in Hamiltonian Cycle.
    // We don't try for 0 as we included 0 as starting point in hamCycle()
    for (int v = 1; v < V; v++)
    {
        /* Check if this vertex can be added to Hamiltonian Cycle */
        if (isSafe(v, graph, path, pos))
        {
            path[pos] = v;
 
            /* recur to construct rest of the path */
            if (hamCycleUtil (graph, path, pos+1) == true)
                return true;
 
            /* If adding vertex v doesn't lead to a solution,
               then remove it */
            path[pos] = -1;
        }
    }
 
    /* If no vertex can be added to Hamiltonian Cycle constructed so far,
       then return false */
    return false;
}
 
/* This function solves the Hamiltonian Cycle problem using Backtracking.
  It mainly uses hamCycleUtil() to solve the problem. It returns false
  if there is no Hamiltonian Cycle possible, otherwise return true and
  prints the path. Please note that there may be more than one solutions,
  this function prints one of the feasible solutions. */
bool hamCycle(bool graph[V][V])
{
    int *path = new int[V];
    for (int i = 0; i < V; i++)
        path[i] = -1;
 
    /* Let us put vertex 0 as the first vertex in the path. If there is
       a Hamiltonian Cycle, then the path can be started from any point
       of the cycle as the graph is undirected */
    path[0] = 0;
    if ( hamCycleUtil(graph, path, 1) == false )
    {
        printf("\nSolution does not exist");
        return false;
    }
 
    printSolution(path);
    return true;
}
 
/* A utility function to print solution */
void printSolution(int path[])
{
    printf ("Solution Exists:"
            " Following is one Hamiltonian Cycle \n");
    for (int i = 0; i < V; i++)
        printf(" %d ", path[i]);
 
    // Let us print the first vertex again to show the complete cycle
    printf(" %d ", path[0]);
    printf("\n");
}
// driver program to test above function
int main()
{

   /* Let us create the following graph


      (0)--(1)--(2)
       |   / \   |
       |  /   \  |
       | /     \ |
      (3)-------(4)    */
   bool graph1[V][V] = {{0, 1, 0, 1, 0},
                      {1, 0, 1, 1, 1},
                      {0, 1, 0, 0, 1},
                      {1, 1, 0, 0, 1},
                      {0, 1, 1, 1, 0},
                     };
 
    // Print the solution
    hamCycle(graph1);
 
   /* Let us create the following graph
      (0)--(1)--(2)
       |   / \   |
       |  /   \  |
       | /     \ |
      (3)       (4)    */
    bool graph2[V][V] = {{0, 1, 0, 1, 0},
                      {1, 0, 1, 1, 1},
                      {0, 1, 0, 0, 1},
                      {1, 1, 0, 0, 0},
                      {0, 1, 1, 0, 0},
                     };
 
    // Print the solution
    hamCycle(graph2);
 
    return 0;
}

Job Assignment Problem using Branch And


Bound
ALGO:

/* findMinCost uses Least() and Add() to maintain the


list of live nodes

Least() finds a live node with least cost, deletes


it from the list and returns it

Add(x) calculates cost of x and adds it to the list


of live nodes

Implements list of live nodes as a min heap */

// Search Space Tree Node


node
{
int job_number;
int worker_number;
node parent;
int cost;
}

// Input: Cost Matrix of Job Assignment problem


// Output: Optimal cost and Assignment of Jobs
algorithm findMinCost (costMatrix mat[][])
{
// Initialize list of live nodes(min-Heap)
// with root of search tree i.e. a Dummy node
while (true)
{
// Find a live node with least estimated cost
E = Least();

// The found node is deleted from the list


// of live nodes
if (E is a leaf node)
{
printSolution();
return;
}

for each child x of E


{
Add(x); // Add x to list of live nodes;
x->parent = E; // Pointer for path to root
}
}

0/1 Knapsack using Branch and Bound


PSUEDOCODE:
Algorithm BB_KNAPSACK(cp, cw, k)
// Description : Solve knapsack problem using branch and bound
// Input:
cp: Current profit, initially 0
cw: Current weight, initially 0
k: Index of item being processed, initially 1
// Output:
fp: Final profit
Fw: Final weight
X: Solution tuple
cp ← 0
cw ← 0
k ← 1
if (cw + w[k] ≤ M) then
Y[k] ← 1
if (k < n) then
BB_KNAPSACK(cp + p[k], cw + w[k], k + 1)
end
if (cp + p[k] > fp) && (k == n) then
fp ← cp + c[k]
fw ← cw + w[k]
X ← Y
end
end
if BOUND(cp, cw, k) ≥ fp then
Y[k] ← 0
if (k < n) then
BB_KNAPSACK(cp, cw, k + 1)
end
if( cp>fp ) && ( k == n ) then
fp ← cp
fw ← cw
X ← Y
end
end

Traveling Salesman Problem using Branch And


Bound
Cost of a tour T = (1/2) * ∑ (Sum of cost of two edges adjacent to u and in the tour T)
where u ∈ V
For every vertex u, if we consider two edges through it in T,and sum their costs. The overall sum for all vertices would
be twice of cost of tour T (We have considered every edge twice.)
(Sum of two tour edges adjacent to u) >= (sum of minimum weight two edges adjacent to u)
Cost of any tour >= 1/2) * ∑ (Sum of cost of two minimum weight edges adjacent to u)
where u ∈ V

CODE:

// C++ program to solve Traveling Salesman Problem


// using Branch and Bound.
#include <bits/stdc++.h>
using namespace std;
const int N = 4;
// final_path[] stores the final solution ie, the
// path of the salesman.
int final_path[N+1];

// visited[] keeps track of the already visited nodes


// in a particular path
bool visited[N];

// Stores the final minimum weight of shortest tour.


int final_res = INT_MAX;

// Function to copy temporary solution to


// the final solution
void copyToFinal(int curr_path[])
{
for (int i=0; i<N; i++)
final_path[i] = curr_path[i];
final_path[N] = curr_path[0];
}

// Function to find the minimum edge cost


// having an end at the vertex i
int firstMin(int adj[N][N], int i)
{
int min = INT_MAX;
for (int k=0; k<N; k++)
if (adj[i][k]<min && i != k)
min = adj[i][k];
return min;
}

// function to find the second minimum edge cost


// having an end at the vertex i
int secondMin(int adj[N][N], int i)
{
int first = INT_MAX, second = INT_MAX;
for (int j=0; j<N; j++)
{
if (i == j)
continue;

if (adj[i][j] <= first)


{
second = first;
first = adj[i][j];
}
else if (adj[i][j] <= second &&
adj[i][j] != first)
second = adj[i][j];
}
return second;
}

// function that takes as arguments:


// curr_bound -> lower bound of the root node
// curr_weight-> stores the weight of the path so far
// level-> current level while moving in the search
// space tree
// curr_path[] -> where the solution is being stored which
// would later be copied to final_path[]
void TSPRec(int adj[N][N], int curr_bound, int curr_weight,
int level, int curr_path[])
{
// base case is when we have reached level N which
// means we have covered all the nodes once
if (level==N)
{
// check if there is an edge from last vertex in
// path back to the first vertex
if (adj[curr_path[level-1]][curr_path[0]] != 0)
{
// curr_res has the total weight of the
// solution we got
int curr_res = curr_weight +
adj[curr_path[level-1]][curr_path[0]];

// Update final result and final path if


// current result is better.
if (curr_res < final_res)
{
copyToFinal(curr_path);
final_res = curr_res;
}
}
return;
}

// for any other level iterate for all vertices to


// build the search space tree recursively
for (int i=0; i<N; i++)
{
// Consider next vertex if it is not same (diagonal
// entry in adjacency matrix and not visited
// already)
if (adj[curr_path[level-1]][i] != 0 &&
visited[i] == false)
{
int temp = curr_bound;
curr_weight += adj[curr_path[level-1]][i];

// different computation of curr_bound for


// level 2 from the other levels
if (level==1)
curr_bound -= ((firstMin(adj, curr_path[level-1]) +
firstMin(adj, i))/2);
else
curr_bound -= ((secondMin(adj, curr_path[level-1]) +
firstMin(adj, i))/2);

// curr_bound + curr_weight is the actual lower bound


// for the node that we have arrived on
// If current lower bound < final_res, we need to explore
// the node further
if (curr_bound + curr_weight < final_res)
{
curr_path[level] = i;
visited[i] = true;

// call TSPRec for the next level


TSPRec(adj, curr_bound, curr_weight, level+1,
curr_path);
}

// Else we have to prune the node by resetting


// all changes to curr_weight and curr_bound
curr_weight -= adj[curr_path[level-1]][i];
curr_bound = temp;

// Also reset the visited array


memset(visited, false, sizeof(visited));
for (int j=0; j<=level-1; j++)
visited[curr_path[j]] = true;
}
}
}

// This function sets up final_path[]


void TSP(int adj[N][N])
{
int curr_path[N+1];

// Calculate initial lower bound for the root node


// using the formula 1/2 * (sum of first min +
// second min) for all edges.
// Also initialize the curr_path and visited array
int curr_bound = 0;
memset(curr_path, -1, sizeof(curr_path));
memset(visited, 0, sizeof(curr_path));

// Compute initial bound


for (int i=0; i<N; i++)
curr_bound += (firstMin(adj, i) + secondMin(adj, i));

// Rounding off the lower bound to an integer


curr_bound = (curr_bound&1)? curr_bound/2 + 1 :
curr_bound/2;

// We start at vertex 1 so the first vertex


// in curr_path[] is 0
visited[0] = true;
curr_path[0] = 0;

// Call to TSPRec for curr_weight equal to


// 0 and level 1
TSPRec(adj, curr_bound, 0, 1, curr_path);
}

// Driver code
int main()
{
//Adjacency matrix for the given graph
int adj[N][N] = { {0, 10, 15, 20},
{10, 0, 35, 25},
{15, 35, 0, 30},
{20, 25, 30, 0}
};

TSP(adj);

printf("Minimum cost : %d\n", final_res);


printf("Path Taken : ");
for (int i=0; i<=N; i++)
printf("%d ", final_path[i]);

return 0;
}

DYNAMIC
// Floyd-Warshall Algorithm in C

#include <stdio.h>

// defining the number of vertices


#define nV 4

#define INF 999

void printMatrix(int matrix[][nV]);

// Implementing floyd warshall algorithm


void floydWarshall(int graph[][nV]) {
int matrix[nV][nV], i, j, k;

for (i = 0; i < nV; i++)


for (j = 0; j < nV; j++)
matrix[i][j] = graph[i][j];

// Adding vertices individually


for (k = 0; k < nV; k++) {
for (i = 0; i < nV; i++) {
for (j = 0; j < nV; j++) {
if (matrix[i][k] + matrix[k][j] < matrix[i][j])
matrix[i][j] = matrix[i][k] + matrix[k][j];
}
}
}
printMatrix(matrix);
}

void printMatrix(int matrix[][nV]) {


for (int i = 0; i < nV; i++) {
for (int j = 0; j < nV; j++) {
if (matrix[i][j] == INF)
printf("%4s", "INF");
else
printf("%4d", matrix[i][j]);
}
printf("\n");
}
}

int main() {
int graph[nV][nV] = {{0, 3, INF, 5},
{2, 0, INF, 4},
{INF, 1, 0, INF},
{INF, INF, 2, 0}};
floydWarshall(graph);
}

Longest Common Subsequence


ALGO:

X and Y be two given sequences

Initialize a table LCS of dimension X.length * Y.length

X.label = X

Y.label = Y

LCS[0][] = 0

LCS[][0] = 0

Start from LCS[1][1]

Compare X[i] and Y[j]

If X[i] = Y[j]

LCS[i][j] = 1 + LCS[i-1, j-1]

Point an arrow to LCS[i][j]

Else

LCS[i][j] = max(LCS[i-1][j], LCS[i][j-1])

Point an arrow to max(LCS[i-1][j], LCS[i][j-1])

Naive STRING MACHING ALGO:


Naive Algorithm:
i) It is the simplest method which uses brute force approach. 
ii) It is a straight forward approach of solving the problem.
iii) It compares first character of pattern with searchable text. If match is found, pointers in both
strings are advanced. If match not found, pointer of text is incremented and pointer ofpattern is
reset. This process is repeated until the end of the text.
iv) It does not require any pre-processing. It directly starts comparing both strings character by
character.
v) Time Complexity = O(m* (n-m))

CODE:
// C program for Naive Pattern Searching algorithm
#include <stdio.h>
#include <string.h>

void search(char* pat, char* txt)


{
int M = strlen(pat);
int N = strlen(txt);

/* A loop to slide pat[] one by one */


for (int i = 0; i <= N - M; i++) {
int j;

/* For current index i, check for pattern match */


for (j = 0; j < M; j++)
if (txt[i + j] != pat[j])
break;

if (j
== M) // if pat[0...M-1] = txt[i, i+1, ...i+M-1]
printf("Pattern found at index %d \n", i);
}
}

// Driver's code
int main()
{
char txt[] = "AABAACAADAABAAABAA";
char pat[] = "AABA";

// Function call
search(pat, txt);
return 0;
}

Rabin-Karp Algorithm
Rabin-Karp algorithm is an algorithm used for searching/matching patterns in the text using a
hash function. Unlike Naive string matching algorithm, it does not travel through every
character in the initial phase rather it filters the characters that do not match and then
performs the comparison.
Code:

Rabin-Karp Algorithm Complexity

The average case and best case complexity of Rabin-Karp algorithm is  O(m + n)  and the worst
case complexity is  O(mn) .
The worst-case complexity occurs when spurious hits occur a number for all the windows.
CODE:
Matrix Chain Multiplication | 
Given the dimension of a sequence of matrices in an array arr[], where the dimension of
the ith matrix is (arr[i-1] * arr[i]), the task is to find the most efficient way to multiply these
matrices together such that the total number of element multiplications is minimum.

You might also like