Category: Blog

https://zain.sweetdishy.com/wp-content/uploads/2025/08/gear.png

  • Maximum Bipartite Matching

    maximum bipartite graph is a type of bipartite graph that has the highest possible number of edges between two sets of vertices.

    bipartite graph is a graph where the set of vertices can be divided into two groups, such that no two vertices within the same group are directly connected. The maximum bipartite graph is one where every vertex in the first group is connected to every vertex in the second group.

    If one group has m vertices and the other has n vertices, the total number of edges in the maximum bipartite graph is:

    Emax = m  n
    

    Properties of Maximum Bipartite Graphs

    Maximum bipartite graphs have the following properties:

    • It has two separate groups of vertices, and edges only connect vertices from different groups.
    • The total number of edges is the maximum possible, which is the product of the number of vertices in each group.
    • Since there are no connections within the same group, it never contains odd-length cycles.
    • The graph can always be colored using just two colorsone for each group of vertices.
    • Maximum bipartite graphs are useful in real-world applications like job assignmentsnetworking, and resource allocation.

    Example of Maximum Bipartite Graph

    Consider the following bipartite graph with four vertices:

    A -- B
    |    |
    C -- D
    

    In this example, the graph has two groups of vertices: {A, C} and {B, D}. The maximum bipartite graph would have the following edges:

    • A — B
    • A — D
    • C — B
    • C — D

    There are four edges in total, which is the maximum possible for this graph.

    Algorithms for Maximum Bipartite Matching

    There are several algorithms to find the maximum bipartite matching in a graph:

    • Hopcroft-Karp Algorithm
    • Ford-Fulkerson Algorithm
    • Hungarian Algorithm
    • Edmonds-Karp Algorithm
    • Augmenting Path Algorithm
    • Network Flow Algorithm

    Code to Find Maximum Bipartite Matching using Hopcroft-Karp Algorithm

    Now, let’s look at the steps to find the maximum bipartite matching in a graph using the Hopcroft-Karp algorithm:

    1. Create a bipartite graph with two sets of vertices.
    2. Initialize an empty matching between the two sets.
    3. While there is an augmenting path in the graph:
        a. Find an augmenting path using a matching algorithm.
        b. Update the matching by adding or removing edges along the path.
    4. Return the maximum matching found.
    

    Let’s look at an example of code to find the maximum bipartite matching in a graph using the Hopcroft-Karp algorithm:

    CC++JavaPython

    // C program to find maximum matching in a bipartite graph#include <stdio.h>#include <stdbool.h>#define M 6#define N 6
    
    bool bpm(int bpGraph[M][N],int u, bool seen[],int matchR[]){for(int v =0; v < N; v++){if((bpGraph[u][v]&&!seen[v])){
             seen[v]= true;if((matchR[v]<0||bpm(bpGraph, matchR[v], seen, matchR))){
                matchR[v]= u;return true;}}}return false;}intmaxBPM(int bpGraph[M][N]){int matchR[N];for(int i =0; i < N; i++)
          matchR[i]=-1;int result =0;for(int u =0; u < M; u++){
          bool seen[N];for(int i =0; i < N; i++)
             seen[i]= false;if(bpm(bpGraph, u, seen, matchR))
             result++;}return result;}intmain(){int bpGraph[M][N]={{0,1,1,0,0,0},{1,0,0,1,0,0},{0,0,1,0,0,0},{0,0,1,1,0,0},{0,0,0,0,0,0},{0,0,0,0,0,1}};printf("Maximum matching is %d\n",maxBPM(bpGraph));return0;}

    Output

    Maximum matching is 5
    

    Applications of Maximum Bipartite Matching

    Maximum bipartite matching algorithms have several real-world applications:

    • Job Assignments: Assigning tasks to workers based on their skills and availability.
    • Networking: Routing data packets through a network to optimize traffic flow.
    • Resource Allocation: Allocating resources like time, money, or equipment to maximize efficiency.
    • Marriage Matching: Pairing individuals based on preferences and compatibility.
    • Project Planning: Scheduling tasks and dependencies to complete projects on time.

    These applications demonstrate the importance of maximum bipartite matching algorithms in solving complex optimization problems.

    Time Complexity of Maximum Bipartite Matching

    The time complexity of finding the maximum bipartite matching in a graph using the Hopcroft-Karp algorithm is O(sqrt(V) * E), where V is the number of vertices and E is the number of edges in the graph. This algorithm is efficient for sparse graphs with a large number of vertices.

    Conclusion

    In this tutorial, we learned about maximum bipartite graphs and how to find the maximum bipartite matching in a graph using various algorithms. We also explored the properties and applications of maximum bipartite graphs in real-world scenarios. By understanding these concepts, you can solve a wide range of optimization problems efficiently.

  • Bellman-Ford Algorithm

    Bellman-Ford is a popular algorithm for finding the shortest path from a starting point (or “source”) to all other points in a graph, even if some edges have negative weights. While its not as fast as Dijkstras algorithm, it has a big advantage: it can handle graphs with negative edge weights.

    How does Bellman-Ford work?

    The way the Bellman-Ford algorithm works is pretty simple. It goes through all the edges of the graph multiple times and tries to improve the shortest path estimates. It “relaxes” the edges by updating the distances until they converge to the correct values.

    It continues to do this for all edges in the graph, ensuring the optimal solution.

    So, even though it might take a bit longer than Dijkstras, its a good tool when negative weights are involved!

    Alogrithm steps for Bellman-Ford

    Heres a step-by-step guide to how the Bellman-Ford algorithm works:

    • Initialization: Start by assigning a distance of 0 to the source node and infinity () to all other nodes.
    • Relaxation: Go through all the edges of the graph and relax them. Relaxing an edge means updating the distance of the destination node if a shorter path is found.
    • Repeat: Repeat the relaxation step for all edges in the graph. Keep doing this until no more improvements can be made.
    • Negative Cycle Detection: After the relaxation step, check for negative cycles. If there are negative cycles in the graph, the algorithm will detect them and report that there is no shortest path.

    Code for Bellman-Ford Algorithm

    Consider a simple graph with vertices and edges.

        (0)
        /   \
      10     15
      /       \
    (1)---5---(3)  
      \       /
       10    10
        \   /
         (4)
           \
            10
             \
              (5)
    

    Example

    Here’s an example code snippet for the Bellman-Ford Shortest Path algorithm in C, C++, Java, and Python:

    CC++JavaPython

    #include <stdio.h>#include <stdlib.h>#include <limits.h>#define MAX_VERTICES 6int graph[MAX_VERTICES][MAX_VERTICES]={{0,10,0,15,0,0},{0,0,0,5,10,0},{0,0,0,0,0,10},{0,0,0,0,0,5},{0,0,0,0,0,10},{0,0,0,0,0,0}};voidbellman_ford(int source){int distance[MAX_VERTICES];for(int i =0; i < MAX_VERTICES; i++){
          distance[i]= INT_MAX;}
       distance[source]=0;for(int i =0; i < MAX_VERTICES -1; i++){for(int u =0; u < MAX_VERTICES; u++){for(int v =0; v < MAX_VERTICES; v++){if(graph[u][v]!=0&& distance[u]!= INT_MAX && distance[u]+ graph[u][v]< distance[v]){
                   distance[v]= distance[u]+ graph[u][v];}}}}for(int u =0; u < MAX_VERTICES; u++){for(int v =0; v < MAX_VERTICES; v++){if(graph[u][v]!=0&& distance[u]!= INT_MAX && distance[u]+ graph[u][v]< distance[v]){printf("Graph contains negative weight cycle\n");return;}}}printf("Vertex   Distance from Source\n");for(int i =0; i < MAX_VERTICES; i++){if(distance[i]== INT_MAX)printf("%d \t\t INF\n", i);elseprintf("%d \t\t %d\n", i, distance[i]);}}intmain(){bellman_ford(0);return0;}

    Output

    Following is the output of the above code:

    Vertex   Distance from Source
    0 		 0
    1 		 10
    2 		 INF
    3 		 15
    4 		 20
    5 		 20
    

    Time Complexity of Bellman-Ford Algorithm

    • The time complexity of the Bellman-Ford algorithm is O(V*E), where V is the number of vertices and E is the number of edges in the graph.
    • The algorithm goes through all the edges of the graph V-1 times, relaxing them to find the shortest path.
    • If there are no negative cycles in the graph, the algorithm will converge to the correct shortest path after V-1 iterations.

    Applications of Bellman-Ford Algorithm

    The Bellman-Ford algorithm is used in various applications, including:

    • Routing Protocols: Bellman-Ford is used in routing protocols like RIP (Routing Information Protocol) to find the shortest path in computer networks.
    • Network Optimization: Its used in network optimization problems to find the shortest path between two points in a graph.
    • Resource Allocation: Bellman-Ford is used in resource allocation problems to find the most efficient way to allocate resources.
    • Graph Analysis: Its used in graph analysis to find the shortest path between two nodes in a graph.

    Conclusion

    In this tutorial, we learned about the Bellman Ford Shortest Path algorithm. It’s code, time complexity, and applications.

  • Convert Infix expression to Postfix expression

    Infix to postfix conversion rearranges math expressions to make them easier for computers to evaluate. In infix notation, operators are between operands (e.g., “A + B”). In postfix notation, operators come after operands (e.g., “A B +”). We use a stack to convert infix to postfix, ensuring the order of operations is preserved.

    What is Infix, Postfix, and Prefix?

    Before jumping into conversion, lets understand the three common types of expressions:

    • Infix: The operator is placed between operands. Example: A + B
    • Postfix (Reverse Polish Notation): The operator comes after the operands. Example: A B +
    • Prefix (Polish Notation): The operator comes before the operands. Example: + A B

    Postfix notation is useful because it eliminates the need for parentheses and follows a simple evaluation process using stacks.

    Why Use a Stack for Conversion?

    Stacks helps us to manage the order of operations (precedence) and parentheses correctly. When scanning an infix expression, we can use a stack to store operators and pop them based on precedence. This way, we can convert infix to postfix without losing the order of operations.

    Infix to Postfix Conversion Algorithm

    The algorithm for converting an infix expression to a postfix expression using a stack is:

    Read the expression from left to right.
    1. If an operand (A-Z, 0-9) is encountered, add it directly to the output.
    2. If an operator is encountered:
       1. Pop operators from the stack to the output if they have higher or equal precedence.
       2. Push the current operator onto the stack.
    3. If an opening parenthesis ( is found, push it onto the stack.
    4. If a closing parenthesis ) is found, pop operators from the stack to the output until an opening parenthesis is encountered.
    5. After scanning the entire expression, pop any remaining operators from the stack to the output.
    

    Operator Precedence

    Operators have different levels of precedence, which determine the order of evaluation:

    • ^ (Exponentiation) Highest precedence
    • *, / (Multiplication, Division) Higher precedence
    • +, - (Addition, Subtraction) Lowest precedence

    When two operators have the same precedence, we evaluate them based on associativity. Most operators are left-to-right associative, except exponentiation, which is right-to-left.

    Example: Convert Infix to Postfix

    Let’s convert the infix expression: A + B * C

    StepScanned CharacterStackPostfix Expression
    1AA
    2++A
    3B+A B
    4*+ *A B
    5C+ *A B C
    6A B C * +

    Final Postfix Expression: A B C * +

    Evaluating Postfix Expression

    Now that we have converted infix to postfix, lets see how to evaluate it:

    • Read the postfix expression from left to right.
    • If an operand is found, push it to the stack.
    • If an operator is found, pop the last two operands from the stack, apply the operation, and push the result back.
    • Continue until the expression is fully processed. The final value in the stack is the result.

    Code for Infix to Postfix Conversion

    Now that we already know the algorithm, lets see how to implement it in C, C++, Java and Python:

    CC++JavaPython

    #include <stdio.h>#include <string.h>#include <ctype.h>#define MAX 100char stack[MAX];int top =-1;voidpush(char item){if(top ==(MAX -1))printf("Stack Overflow\n");else
          stack[++top]= item;}charpop(){if(top ==-1){printf("Stack Underflow\n");return'\0';}return stack[top--];}intprecedence(char symbol){switch(symbol){case'^':return3;case'*':case'/':return2;case'+':case'-':return1;default:return0;}}voidinfixToPostfix(char infix[],char postfix[]){int i =0, j =0;char symbol;push('(');strcat(infix,")");while(infix[i]!='\0'){
          symbol = infix[i];if(symbol ==' '){
             i++;continue;}if(symbol =='(')push(symbol);elseif(isalnum(symbol))
             postfix[j++]= symbol;elseif(symbol ==')'){while(top !=-1&& stack[top]!='(')
                postfix[j++]=pop();pop();}else{while(top !=-1&&precedence(stack[top])>=precedence(symbol))
                postfix[j++]=pop();push(symbol);}
          i++;}
       postfix[j]='\0';}intmain(){char infix[MAX]="A + B * C";char postfix[MAX];printf("Infix Expression: %s\n", infix);infixToPostfix(infix, postfix);printf("Postfix Expression: %s\n", postfix);return0;}

    Output

    Following is the output of the above code:

    Enter Infix Expression: A + B * C
    Postfix Expression: ABC*+
    

    Applications of Postfix Notation

    Following are some common applications of postfix notation:

    • Used in compilers to evaluate expressions without needing parentheses.
    • Helps in designing calculators where stack-based evaluation is required.
    • Used in Expression Trees for easy computation.

    Conclusion

    Infix notation is how we naturally write mathematical expressions, but computers prefer postfix because its easier to process. We can use stack for easy Infix to Postfix conversion. Understanding this concept is crucial for solving problems related to expression evaluation and compiler design.

  • Travelling Salesman using Approximation Algorithm

    We have already discussed the travelling salesperson problem using the greedy and dynamic programming approaches, and it is established that solving the travelling salesperson problems for the perfect optimal solutions is not possible in polynomial time.

    Therefore, the approximation solution is expected to find a near optimal solution for this NP-Hard problem. However, an approximate algorithm is devised only if the cost function (which is defined as the distance between two plotted points) in the problem satisfies triangle inequality.

    The triangle inequality is satisfied only if the cost function c, for all the vertices of a triangle u, v and w, satisfies the following equation

                     c(u, w) c(u, v)+c(v, w)
    

    It is usually automatically satisfied in many applications.

    Travelling Salesperson Approximation Algorithm

    The travelling salesperson approximation algorithm requires some prerequisite algorithms to be performed so we can achieve a near optimal solution. Let us look at those prerequisite algorithms briefly −

    Minimum Spanning Tree − The minimum spanning tree is a tree data structure that contains all the vertices of main graph with minimum number of edges connecting them. We apply prims algorithm for minimum spanning tree in this case.

    Pre-order Traversal − The pre-order traversal is done on tree data structures where a pointer is walked through all the nodes of the tree in a [root left child right child] order.

    Algorithm

    Step 1 − Choose any vertex of the given graph randomly as the starting and ending point.

    Step 2 − Construct a minimum spanning tree of the graph with the vertex chosen as the root using prims algorithm.

    Step 3 − Once the spanning tree is constructed, pre-order traversal is performed on the minimum spanning tree obtained in the previous step.

    Step 4 − The pre-order solution obtained is the Hamiltonian path of the travelling salesperson.

    Pseudocode

    APPROX_TSP(G, c)
       r <- root node of the minimum spanning tree
       T <- MST_Prim(G, c, r)
       visited = {}
       for i in range V:
          H <- Preorder_Traversal(G)
          visited = {H}
    

    Analysis

    The approximation algorithm of the travelling salesperson problem is a 2-approximation algorithm if the triangle inequality is satisfied.

    To prove this, we need to show that the approximate cost of the problem is double the optimal cost. Few observations that support this claim would be as follows −

    • The cost of minimum spanning tree is never less than the cost of the optimal Hamiltonian path. That is, c(M) c(H*).
    • The cost of full walk is also twice as the cost of minimum spanning tree. A full walk is defined as the path traced while traversing the minimum spanning tree preorderly. Full walk traverses every edge present in the graph exactly twice. Thereore, c(W) = 2c(T)
    • Since the preorder walk path is less than the full walk path, the output of the algorithm is always lower than the cost of the full walk.

    Example

    Let us look at an example graph to visualize this approximation algorithm −

    approximation_algorithm

    Solution

    Consider vertex 1 from the above graph as the starting and ending point of the travelling salesperson and begin the algorithm from here.

    Step 1

    Starting the algorithm from vertex 1, construct a minimum spanning tree from the graph. To learn more about constructing a minimum spanning tree, please click here.

    constructing_minimum_spanning_tree

    Step 2

    Once, the minimum spanning tree is constructed, consider the starting vertex as the root node (i.e., vertex 1) and walk through the spanning tree preorderly.

    Rotating the spanning tree for easier interpretation, we get −

    Rotating_spanning_tree

    The preorder traversal of the tree is found to be − 1 → 2 → 5 → 6 → 3 → 4

    Step 3

    Adding the root node at the end of the traced path, we get, 1 → 2 → 5 → 6 → 3 → 4 → 1

    This is the output Hamiltonian path of the travelling salesman approximation problem. The cost of the path would be the sum of all the costs in the minimum spanning tree, i.e., 55.

    Implementation

    Following are the implementations of the above approach in various programming langauges −

    CC++JavaPython

    #include <stdio.h>#include <stdbool.h>#include <limits.h>#define V 6 // Number of vertices in the graph// Function to find the minimum key vertex from the set of vertices not yet included in MSTintfindMinKey(int key[], bool mstSet[]){int min = INT_MAX, min_index;for(int v =0; v < V; v++){if(mstSet[v]== false && key[v]< min){
             min = key[v];
             min_index = v;}}return min_index;}// Function to perform Prim's algorithm to find the Minimum Spanning Tree (MST)voidprimMST(int graph[V][V],int parent[]){int key[V];
       bool mstSet[V];for(int i =0; i < V; i++){
          key[i]= INT_MAX;
          mstSet[i]= false;}
       key[0]=0;
       parent[0]=-1;for(int count =0; count < V -1; count++){int u =findMinKey(key, mstSet);
          mstSet[u]= true;for(int v =0; v < V; v++){if(graph[u][v]&& mstSet[v]== false && graph[u][v]< key[v]){
                parent[v]= u;
                key[v]= graph[u][v];}}}}// Function to print the preorder traversal of the Minimum Spanning TreevoidprintPreorderTraversal(int parent[]){printf("The preorder traversal of the tree is found to be  ");for(int i =1; i < V; i++){printf("%d  ", parent[i]);}printf("\n");}// Main function for the Traveling Salesperson Approximation AlgorithmvoidtspApproximation(int graph[V][V]){int parent[V];int root =0;// Choosing vertex 0 as the starting and ending point// Find the Minimum Spanning Tree using Prim's AlgorithmprimMST(graph, parent);// Print the preorder traversal of the Minimum Spanning TreeprintPreorderTraversal(parent);// Print the Hamiltonian path (preorder traversal with the starting point added at the end)printf("Adding the root node at the end of the traced path ");for(int i =0; i < V; i++){printf("%d  ", parent[i]);}printf("%d  %d\n", root, parent[0]);// Calculate and print the cost of the Hamiltonian pathint cost =0;for(int i =1; i < V; i++){
          cost += graph[parent[i]][i];}// The cost of the path would be the sum of all the costs in the minimum spanning tree.printf("Sum of all the costs in the minimum spanning tree %d.\n", cost);}intmain(){// Example graph represented as an adjacency matrixint graph[V][V]={{0,3,1,6,0,0},{3,0,5,0,3,0},{1,5,0,5,6,4},{6,0,5,0,0,2},{0,3,6,0,0,6},{0,0,4,2,6,0}};tspApproximation(graph);return0;}

    Output

    The preorder traversal of the tree is found to be  0  0  5  1  2  
    Adding the root node at the end of the traced path -1  0  0  5  1  2  0  -1
    Sum of all the costs in the minimum spanning tree 13.
  • Set Cover Problem

    The set cover algorithm provides solution to many real-world resource allocating problems. For instance, consider an airline assigning crew members to each of their airplanes such that they have enough people to fulfill the requirements for the journey. They take into account the flight timings, the duration, the pit-stops, availability of the crew to assign them to the flights. This is where set cover algorithm comes into picture.

    Given a universal set U, containing few elements which are all divided into subsets. Considering the collection of these subsets as S = {S1, S2, S3, S4… Sn}, the set cover algorithm finds the minimum number of subsets such that they cover all the elements present in the universal set.

    universal_set

    As shown in the above diagram, the dots represent the elements present in the universal set U that are divided into different sets, S = {S1, S2, S3, S4, S5, S6}. The minimum number of sets that need to be selected to cover all the elements will be the optimal output = {S1, S2, S3}.

    Set Cover Algorithm

    The set cover takes the collection of sets as an input and and returns the minimum number of sets required to include all the universal elements.

    The set cover algorithm is an NP-Hard problem and a 2-approximation greedy algorithm.

    Algorithm

    Step 1 − Initialize Output = {} where Output represents the output set of elements.

    Step 2 − While the Output set does not include all the elements in the universal set, do the following −

    • Find the cost-effectiveness of every subset present in the universal set using the formula, Cost(Si)Si−Output
    • Find the subset with minimum cost effectiveness for each iteration performed. Add the subset to the Output set.

    Step 3 − Repeat Step 2 until there is no elements left in the universe. The output achieved is the final Output set.

    Pseudocode

    APPROX-GREEDY-SET_COVER(X, S)
       U = X
       OUTPUT = 
       while U  
          select Si  S which has maximum |SiU|
       U = U  S
       OUTPUT = OUTPUT {Si}
    return OUTPUT
    

    Analysis

    assuming the overall number of elements equals the overall number of sets (|X| = |S|), the code runs in time O(|X|3)

    Example

    Set_Cover_Algorithm

    Let us look at an example that describes the approximation algorithm for the set covering problem in more detail

    S1 = {1, 2, 3, 4}                cost(S1) = 5
    S2 = {2, 4, 5, 8, 10}            cost(S2) = 10
    S3 = {1, 3, 5, 7, 9, 11, 13}     cost(S3) = 20
    S4 = {4, 8, 12, 16, 20}          cost(S4) = 12
    S5 = {5, 6, 7, 8, 9}             cost(S5) = 15
    

    Step 1

    The output set, Output =

    Find the cost effectiveness of each set for no elements in the output set,

    S1 = cost(S1) / (S1  Output) = 5 / (4  0)
    S2 = cost(S2) / (S2  Output) = 10 / (5  0)
    S3 = cost(S3) / (S3  Output) = 20 / (7  0)
    S4 = cost(S4) / (S4  Output) = 12 / (5  0)
    S5 = cost(S5) / (S5  Output) = 15 / (5  0)
    

    The minimum cost effectiveness in this iteration is achieved at S1, therefore, the subset added to the output set, Output = {S1} with elements {1, 2, 3, 4}

    Step 2

    Find the cost effectiveness of each set for the new elements in the output set,

    S2 = cost(S2) / (S2  Output) = 10 / (5  4)
    S3 = cost(S3) / (S3  Output) = 20 / (7  4)
    S4 = cost(S4) / (S4  Output) = 12 / (5  4)
    S5 = cost(S5) / (S5  Output) = 15 / (5  4)
    

    The minimum cost effectiveness in this iteration is achieved at S3, therefore, the subset added to the output set, Output = {S1, S3} with elements {1, 2, 3, 4, 5, 7, 9, 11, 13}.

    Step 3

    Find the cost effectiveness of each set for the new elements in the output set,

    S2 = cost(S2) / (S2  Output) = 10 / |(5  9)|
    S4 = cost(S4) / (S4  Output) = 12 / |(5  9)|
    S5 = cost(S5) / (S5  Output) = 15 / |(5  9)|
    

    The minimum cost effectiveness in this iteration is achieved at S2, therefore, the subset added to the output set, Output = {S1, S3, S2} with elements {1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 13}

    Step 4

    Find the cost effectiveness of each set for the new elements in the output set,

    S4 = cost(S4) / (S4  Output) = 12 / |(5  11)|
    S5 = cost(S5) / (S5  Output) = 15 / |(5  11)|
    

    The minimum cost effectiveness in this iteration is achieved at S4, therefore, the subset added to the output set, Output = {S1, S3, S2, S4} with elements {1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12, 13, 16, 20}

    Step 5

    Find the cost effectiveness of each set for the new elements in the output set,

    S5 = cost(S5) / (S5  Output) = 15 / |(5  14)|
    

    The minimum cost effectiveness in this iteration is achieved at S5, therefore, the subset added to the output set, Output = {S1, S3, S2, S4, S5} with elements {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16, 20}

    The final output that covers all the elements present in the universal finite set is, Output = {S1, S3, S2, S4, S5}.

    Implementation

    Following are the implementations of the above approach in various programming langauges −

    CC++JavaPython

    #include <stdio.h>#define MAX_SETS 100#define MAX_ELEMENTS 1000intsetCover(int X[],int S[][MAX_ELEMENTS],int numSets,int numElements,int output[]){int U[MAX_ELEMENTS];for(int i =0; i < numElements; i++){
          U[i]= X[i];}int selectedSets[MAX_SETS];for(int i =0; i < MAX_SETS; i++){
          selectedSets[i]=0;// Initialize all to 0 (not selected)}int outputIdx =0;while(outputIdx < numSets){// Ensure we don't exceed the maximum number of setsint maxIntersectionSize =0;int selectedSetIdx =-1;// Find the set Si with the maximum intersection with Ufor(int i =0; i < numSets; i++){if(selectedSets[i]==0){// Check if the set is not already selectedint intersectionSize =0;for(int j =0; j < numElements; j++){if(U[j]&& S[i][j]){
                      intersectionSize++;}}if(intersectionSize > maxIntersectionSize){
                   maxIntersectionSize = intersectionSize;
                   selectedSetIdx = i;}}}// If no set found, break from the loopif(selectedSetIdx ==-1){break;}// Mark the selected set as "selected" in the array
          selectedSets[selectedSetIdx]=1;// Remove the elements covered by the selected set from Ufor(int j =0; j < numElements; j++){
              U[j]= U[j]- S[selectedSetIdx][j];}// Add the selected set to the output
          output[outputIdx++]= selectedSetIdx;}return outputIdx;}intmain(){int X[MAX_ELEMENTS]={1,2,3,4,5,6,7,8,9,10};int S[MAX_SETS][MAX_ELEMENTS]={{1,1,0,0,0,0,0,0,0,0},{0,1,1,1,0,0,0,0,0,0},{0,0,0,1,1,1,0,0,0,0},{0,0,0,0,0,1,1,1,0,0},{0,0,0,0,0,0,0,1,1,1}};int numSets =5;int numElements =10;int output[MAX_SETS];int numSelectedSets =setCover(X, S, numSets, numElements, output);printf("Selected Sets: ");for(int i =0; i < numSelectedSets; i++){printf("%d ", output[i]);}printf("\n");return0;}

    Output

    Selected Sets: 1 2 3 4 0
  • Vertex Cover Algorithm

    Have you ever wondered about the placement of traffic cameras? That how they are efficiently placed without wasting too much budget from the government? The answer to that comes in the form of vertex-cover algorithm. The positions of the cameras are chosen in such a way that one camera covers as many roads as possible, i.e., we choose junctions and make sure the camera covers as much area as possible.

    vertex-cover of an undirected graph G = (V,E) is the subset of vertices of the graph such that, for all the edges (u,v) in the graph,u and v ∈ V. The junction is treated as the node of a graph and the roads as the edges. The algorithm finds the minimum set of junctions that cover maximum number of roads.

    It is a minimization problem since we find the minimum size of the vertex cover the size of the vertex cover is the number of vertices in it. The optimization problem is an NP-Complete problem and hence, cannot be solved in polynomial time; but what can be found in polynomial time is the near optimal solution.

    Vertex Cover Algorithm

    The vertex cover approximation algorithm takes an undirected graph as an input and is executed to obtain a set of vertices that is definitely twice as the size of optimal vertex cover.

    The vertex cover is a 2-approximation algorithm.

    Algorithm

    Step 1 − Select any random edge from the input graph and mark all the edges that are incident on the vertices corresponding to the selected edge.

    Step 2 − Add the vertices of the arbitrary edge to an output set.

    Step 3 − Repeat Step 1 on the remaining unmarked edges of the graph and add the vertices chosen to the output until theres no edge left unmarked.

    Step 4 − The final output set achieved would be the near-optimal vertex cover.

    Pseudocode

    APPROX-VERTEX_COVER (G: Graph)
    c ← { }
    E ← E[G]
    while E is not empty do
       Let (u, v) be an arbitrary edge of E
       c ← c U {u, v}
       Remove from E every edge incident on either u or v
    return c
    

    Example

    The set of edges of the given graph is −

    {(1,6),(1,2),(1,4),(2,3),(2,4),(6,7),(4,7),(7,8),(3,5),(8,5)}
    
    Vertex_Cover_Problem

    Now, we start by selecting an arbitrary edge (1,6). We eliminate all the edges, which are either incident to vertex 1 or 6 and we add edge (1,6) to cover.

    arbitrary_edge

    In the next step, we have chosen another edge (2,3) at random.

    chosen_another_edge

    Now we select another edge (4,7).

    select_another_edge

    We select another edge (8,5).

    another edge 8 to 5

    Hence, the vertex cover of this graph is {1,6,2,3,4,7,5,8}.

    Analysis

    It is easy to see that the running time of this algorithm is O(V + E), using adjacency list to represent E’.

    Implementation

    Following are the implementations of the above approach in various programming langauges −

    CC++JavaPython

    #include <stdio.h>#include <stdbool.h>#define MAX_VERTICES 100int graph[MAX_VERTICES][MAX_VERTICES];
    bool included[MAX_VERTICES];// Function to find Vertex Cover using the APPROX-VERTEX_COVER algorithmvoidapproxVertexCover(int vertices,int edges){
       bool edgesRemaining[MAX_VERTICES][MAX_VERTICES];for(int i =0; i < vertices; i++){for(int j =0; j < vertices; j++){
             edgesRemaining[i][j]= graph[i][j];}}while(edges >0){int u, v;for(int i =0; i < vertices; i++){for(int j =0; j < vertices; j++){if(edgesRemaining[i][j]){
                   u = i;
                   v = j;break;}}}
          included[u]= included[v]= true;for(int i =0; i < vertices; i++){
             edgesRemaining[u][i]= edgesRemaining[i][u]= false;
             edgesRemaining[v][i]= edgesRemaining[i][v]= false;}
          edges--;}}intmain(){int vertices =8;int edges =10;int edgesData[10][2]={{1,6},{1,2},{1,4},{2,3},{2,4},{6,7},{4,7},{7,8},{3,5},{8,5}};for(int i =0; i < edges; i++){int u = edgesData[i][0];int v = edgesData[i][1];
          graph[u][v]= graph[v][u]=1;}approxVertexCover(vertices, edges);printf("Vertex Cover: ");for(int i =1; i <= vertices; i++){if(included[i]){printf("%d ", i);}}printf("\n");return0;}

    Output

    Vertex Cover: 1 3 4 5 6 7 
  • Approximation Algorithms

    Approximation Algorithms

    Approximation algorithms are algorithms designed to solve problems that are not solvable in polynomial time for approximate solutions. These problems are known as NP complete problems. These problems are significantly effective to solve real world problems, therefore, it becomes important to solve them using a different approach.

    NP complete problems can still be solved in three cases: the input could be so small that the execution time is reduced, some problems can still be classified into problems that can be solved in polynomial time, or use approximation algorithms to find near-optima solutions for the problems.

    This leads to the concept of performance ratios of an approximation problem.

    Performance Ratios

    The main idea behind calculating the performance ratio of an approximation algorithm, which is also called as an approximation ratio, is to find how close the approximate solution is to the optimal solution.

    The approximate ratio is represented using (n) where n is the input size of the algorithm, C is the near-optimal solution obtained by the algorithm, C* is the optimal solution for the problem. The algorithm has an approximate ratio of (n) if and only if −

    max{CC∗,C∗C}≤ρ(n)

    The algorithm is then called a (n)-approximation algorithm. Approximation Algorithms can be applied on two types of optimization problems: minimization problems and maximization problems. If the optimal solution of the problem is to find the maximum cost, the problem is known as the maximization problem; and if the optimal solution of the problem is to find the minimum cost, then the problem is known as a minimization problem.

    For maximization problems, the approximation ratio is calculated by C*/C since 0 C C*. For minimization problems, the approximation ratio is calculated by C/C* since 0 C* C.

    Assuming that the costs of approximation algorithms are all positive, the performance ratio is well defined and will not be less than 1. If the value is 1, that means the approximate algorithm generates the exact optimal solution.

    Examples

    Few popular examples of the approximation algorithms are −

    • Vertex Cover Algorithm
    • Set Cover Problem
    • Travelling Salesman Problem (Approximation Approach)
    • The Subset Sum Problem
  • PHP – String Operators

    There are two operators in PHP for working with string data types: concatenation operator (“.”) and the concatenation assignment operator (“.=”). Read this chapter to learn how these operators work in PHP.

    Concatenation Operator in PHP

    The dot operator (“.”) is PHP’s concatenation operator. It joins two string operands (characters of right hand string appended to left hand string) and returns a new string.

    $third=$first.$second;

    Example

    The following example shows how you can use the concatenation operator in PHP −

    <?php
       $x="Hello";
       $y=" ";
       $z="PHP";
       $str=$x . $y . $z;
       echo $str;
    ?>

    Output

    It will produce the following output −

    Hello PHP
    

    Concatenation Assignment Operator in PHP

    PHP also has the “.=” operator which can be termed as the concatenation assignment operator. It updates the string on its left by appending the characters of right hand operand.

    $leftstring.=$rightstring;

    Example

    The following example uses the concatenation assignment operator. Two string operands are concatenated returning the updated contents of string on the left side −

    <?php
       $x="Hello ";
       $y="PHP";
       $x .= $y;
       echo $x;
    ?>

    Output

    It will produce the following result −

    Hello PHP
    

    Working with Variables and Strings

    In the below PHP code we will try to work with variables and strings. So you may know that you can also concatenate strings with variables in PHP. Here two variables are combined with other strings to create a sentence −

    <?php
       $name = "Ankit";
       $age = 25;
       $sentence = "My name is " . $name . " and I am " . $age . " years old.";
       echo $sentence;
    ?>

    Output

    This will generate the below output −

    My name is Ankit and I am 25 years old.
    

    Using Concatenation in Loops

    Now the below code demonstrate how concatenation can be used inside loops to create a long string. See the example below −

    <?php
       $result = "";
       for ($i = 1; $i <= 5; $i++) {
          $result .= "Number " . $i . "\n";
       }
       echo $result;
    ?>

    Output

    This will create the below output −

    Number 1
    Number 2
    Number 3
    Number 4
    Number 5
    

    Combining Strings with Different Data Types

    In the following example, we are showing how you can combine different data types with strings and show the output −

    <?php
       $price = 100;
       $message = "The price is " . $price . " rupees.";
       echo $message;
    ?>

    Output

    Following is the output of the above code −

    The price is 100 rupees.