Algoritmo de Karger para corte mínimo | Conjunto 1 (Introducción e Implementación)

Dado un gráfico no dirigido y no ponderado, encuentre el corte más pequeño (el menor número de aristas que desconecta el gráfico en dos componentes). 
El gráfico de entrada puede tener bordes paralelos.

Por ejemplo, considere el siguiente ejemplo, el corte más pequeño tiene 2 bordes.

Kargerfirst

Una solución simple utiliza el algoritmo de corte s-t basado en Max-Flow para encontrar el corte mínimo. Considere cada par de vértices como fuente ‘s’ y sumidero ‘t’, y llame al algoritmo de corte de st mínimo para encontrar el corte de st. Vuelva al mínimo de todos los cortes de st. La mejor complejidad temporal posible de este algoritmo es O(V 5 ) para un gráfico. [¿Cómo? hay un total de V 2 pares posibles y el algoritmo de corte st para un par toma el tiempo O(V*E) y E = O(V 2 )]. 

A continuación se muestra el algoritmo de Karger simple para este propósito. A continuación, el algoritmo de Karger se puede implementar en el tiempo O(E) = O(V 2 ). 

1)  Initialize contracted graph CG as copy of original graph
2)  While there are more than 2 vertices.
      a) Pick a random edge (u, v) in the contracted graph.
      b) Merge (or contract) u and v into a single vertex (update 
         the contracted graph).
      c) Remove self-loops
3) Return cut represented by two vertices.

Entendamos el algoritmo anterior a través del ejemplo dado.
Deje que el primer vértice elegido al azar sea ‘ a ‘ que conecta los vértices 0 y 1. Eliminamos este borde y contraemos el gráfico (combinamos los vértices 0 y 1). Obtenemos el siguiente gráfico. 

Karger2

Deje que el siguiente borde elegido al azar sea ‘d’. Eliminamos este borde y combinamos los vértices (0,1) y 3. 

Karger3

Necesitamos eliminar los bucles automáticos en el gráfico. Entonces eliminamos el borde ‘c’ 

Karger4

Ahora el gráfico tiene dos vértices, así que nos detenemos. El número de aristas en el gráfico resultante es el corte producido por el algoritmo de Karger.
El algoritmo de Karger es un algoritmo de Monte Carlo y el corte producido por él puede no ser mínimo. Por ejemplo, el siguiente diagrama muestra que un orden diferente de selección de bordes aleatorios produce un corte mínimo de tamaño 3.

Karger1

A continuación se muestra la implementación en C++ del algoritmo anterior. El gráfico de entrada se representa como una colección de aristas y la estructura de datos de búsqueda de unión se utiliza para realizar un seguimiento de los componentes. 
 

C++

// Karger's algorithm to find Minimum Cut in an
// undirected, unweighted and connected graph.
#include <iostream>
//#include <stdlib.h>
#include <time.h>
 
// a structure to represent a unweighted edge in graph
struct Edge
{
    int src, dest;
};
 
// a structure to represent a connected, undirected
// and unweighted graph as a collection of edges.
struct Graph
{
    // V-> Number of vertices, E-> Number of edges
    int V, E;
 
    // graph is represented as an array of edges.
    // Since the graph is undirected, the edge
    // from src to dest is also edge from dest
    // to src. Both are counted as 1 edge here.
    Edge* edge;
};
 
// A structure to represent a subset for union-find
struct subset
{
    int parent;
    int rank;
};
 
// Function prototypes for union-find (These functions are defined
// after kargerMinCut() )
int find(struct subset subsets[], int i);
void Union(struct subset subsets[], int x, int y);
 
// A very basic implementation of Karger's randomized
// algorithm for finding the minimum cut. Please note
// that Karger's algorithm is a Monte Carlo Randomized algo
// and the cut returned by the algorithm may not be
// minimum always
int kargerMinCut(struct Graph* graph)
{
    // Get data of given graph
    int V = graph->V, E = graph->E;
    Edge *edge = graph->edge;
 
    // Allocate memory for creating V subsets.
    struct subset *subsets = new subset[V];
 
    // Create V subsets with single elements
    for (int v = 0; v < V; ++v)
    {
        subsets[v].parent = v;
        subsets[v].rank = 0;
    }
 
    // Initially there are V vertices in
    // contracted graph
    int vertices = V;
 
    // Keep contracting vertices until there are
    // 2 vertices.
    while (vertices > 2)
    {
       // Pick a random edge
       int i = rand() % E;
 
       // Find vertices (or sets) of two corners
       // of current edge
       int subset1 = find(subsets, edge[i].src);
       int subset2 = find(subsets, edge[i].dest);
 
       // If two corners belong to same subset,
       // then no point considering this edge
       if (subset1 == subset2)
         continue;
 
       // Else contract the edge (or combine the
       // corners of edge into one vertex)
       else
       {
          printf("Contracting edge %d-%d\n",
                 edge[i].src, edge[i].dest);
          vertices--;
          Union(subsets, subset1, subset2);
       }
    }
 
    // Now we have two vertices (or subsets) left in
    // the contracted graph, so count the edges between
    // two components and return the count.
    int cutedges = 0;
    for (int i=0; i<E; i++)
    {
        int subset1 = find(subsets, edge[i].src);
        int subset2 = find(subsets, edge[i].dest);
        if (subset1 != subset2)
          cutedges++;
    }
 
    return cutedges;
}
 
// A utility function to find set of an element i
// (uses path compression technique)
int find(struct subset subsets[], int i)
{
    // find root and make root as parent of i
    // (path compression)
    if (subsets[i].parent != i)
      subsets[i].parent =
             find(subsets, subsets[i].parent);
 
    return subsets[i].parent;
}
 
// A function that does union of two sets of x and y
// (uses union by rank)
void Union(struct subset subsets[], int x, int y)
{
    int xroot = find(subsets, x);
    int yroot = find(subsets, y);
 
    // Attach smaller rank tree under root of high
    // rank tree (Union by Rank)
    if (subsets[xroot].rank < subsets[yroot].rank)
        subsets[xroot].parent = yroot;
    else if (subsets[xroot].rank > subsets[yroot].rank)
        subsets[yroot].parent = xroot;
 
    // If ranks are same, then make one as root and
    // increment its rank by one
    else
    {
        subsets[yroot].parent = xroot;
        subsets[xroot].rank++;
    }
}
 
// Creates a graph with V vertices and E edges
struct Graph* createGraph(int V, int E)
{
    Graph* graph = new Graph;
    graph->V = V;
    graph->E = E;
    graph->edge = new Edge[E];
    return graph;
}
 
// Driver program to test above functions
int main()
{
    /* Let us create following unweighted graph
        0------1
        | \    |
        |   \  |
        |     \|
        2------3   */
    int V = 4;  // Number of vertices in graph
    int E = 5;  // Number of edges in graph
    struct Graph* graph = createGraph(V, E);
 
    // add edge 0-1
    graph->edge[0].src = 0;
    graph->edge[0].dest = 1;
 
    // add edge 0-2
    graph->edge[1].src = 0;
    graph->edge[1].dest = 2;
 
    // add edge 0-3
    graph->edge[2].src = 0;
    graph->edge[2].dest = 3;
 
    // add edge 1-3
    graph->edge[3].src = 1;
    graph->edge[3].dest = 3;
 
    // add edge 2-3
    graph->edge[4].src = 2;
    graph->edge[4].dest = 3;
 
    // Use a different seed value for every run.
    srand(time(NULL));
 
    printf("\nCut found by Karger's randomized algo is %d\n",
           kargerMinCut(graph));
 
    return 0;
}

Java

//Java program to implement the Karger's algorithm to find Minimum Cut in an
// undirected, unweighted and connected graph.
 
import java.io.*;
import java.util.*;
 
class GFG {
     
    // a structure to represent a unweighted edge in graph
    public static class Edge
    {
        int src, dest;
        Edge(int s, int d){
            this.src = s;
            this.dest = d;
        }
    }
      
    // a structure to represent a connected, undirected
    // and unweighted graph as a collection of edges.
    public static class Graph
    {
        // V-> Number of vertices, E-> Number of edges
        int V, E;
      
        // graph is represented as an array of edges.
        // Since the graph is undirected, the edge
        // from src to dest is also edge from dest
        // to src. Both are counted as 1 edge here.
        Edge edge[];
        Graph(int v, int e){
            this.V = v;
            this.E = e;
            this.edge = new Edge[e];
            /*for(int i=0;i<e;i++){
                this.edge[i]=new Edge(-1,-1);
            }*/
        }
    }
      
    // A structure to represent a subset for union-find
    public static class subset
    {
        int parent;
        int rank;
        subset(int p, int r){
            this.parent = p;
            this.rank = r;
        }
    }
     
    // A very basic implementation of Karger's randomized
    // algorithm for finding the minimum cut. Please note
    // that Karger's algorithm is a Monte Carlo Randomized algo
    // and the cut returned by the algorithm may not be
    // minimum always
    public static int kargerMinCut(Graph graph)
    {
        // Get data of given graph
        int V = graph.V, E = graph.E;
        Edge edge[] = graph.edge;
      
        // Allocate memory for creating V subsets.
        subset subsets[] = new subset[V];
      
        // Create V subsets with single elements
        for (int v = 0; v < V; ++v)
        {
            subsets[v] = new subset(v,0);
        }
      
        // Initially there are V vertices in
        // contracted graph
        int vertices = V;
      
        // Keep contracting vertices until there are
        // 2 vertices.
        while (vertices > 2)
        {
           // Pick a random edge
           int i = ((int)(Math.random()*10)) % E;
      
           // Find vertices (or sets) of two corners
           // of current edge
           int subset1 = find(subsets, edge[i].src);
           int subset2 = find(subsets, edge[i].dest);
      
           // If two corners belong to same subset,
           // then no point considering this edge
           if (subset1 == subset2){
               continue;
           }
      
           // Else contract the edge (or combine the
           // corners of edge into one vertex)
           else
           {
              System.out.println("Contracting edge "+edge[i].src+"-"+edge[i].dest);
              vertices--;
              Union(subsets, subset1, subset2);
           }
        }
      
        // Now we have two vertices (or subsets) left in
        // the contracted graph, so count the edges between
        // two components and return the count.
        int cutedges = 0;
        for (int i=0; i<E; i++)
        {
            int subset1 = find(subsets, edge[i].src);
            int subset2 = find(subsets, edge[i].dest);
            if (subset1 != subset2){
                cutedges++;
            }
        }
      
        return cutedges;
    }
      
    // A utility function to find set of an element i
    // (uses path compression technique)
    public static int find(subset subsets[], int i)
    {
        // find root and make root as parent of i
        // (path compression)
        if (subsets[i].parent != i){
            subsets[i].parent = find(subsets, subsets[i].parent);
        }
        return subsets[i].parent;
    }
      
    // A function that does union of two sets of x and y
    // (uses union by rank)
    public static void Union(subset subsets[], int x, int y)
    {
        int xroot = find(subsets, x);
        int yroot = find(subsets, y);
      
        // Attach smaller rank tree under root of high
        // rank tree (Union by Rank)
        if (subsets[xroot].rank < subsets[yroot].rank){
            subsets[xroot].parent = yroot;
        }else{
            if (subsets[xroot].rank > subsets[yroot].rank){
                subsets[yroot].parent = xroot;
            }
            // If ranks are same, then make one as root and
            // increment its rank by one
            else
            {
                subsets[yroot].parent = xroot;
                subsets[xroot].rank++;
            }
        }
    }
     
    // Driver program to test above functions
    public static void main (String[] args) {
        /* Let us create following unweighted graph
            0------1
            | \    |
            |   \  |
            |     \|
            2------3   */
        int V = 4;  // Number of vertices in graph
        int E = 5;  // Number of edges in graph
         
        // Creates a graph with V vertices and E edges
        Graph graph = new Graph(V, E);
      
        // add edge 0-1
        graph.edge[0] = new Edge(0,1);
      
        // add edge 0-2
        graph.edge[1] = new Edge(0,2);
      
        // add edge 0-3
        graph.edge[2] = new Edge(0,3);
      
        // add edge 1-3
        graph.edge[3] = new Edge(1,3);
      
        // add edge 2-3
        graph.edge[4] = new Edge(2,3);
      
        System.out.println("Cut found by Karger's randomized algo is "+kargerMinCut(graph));
    }
}
//This code is contributed by shruti456rawal
Producción

Contracting edge 0-1
Contracting edge 1-3

Cut found by Karger's randomized algo is 2

Tenga en cuenta que el programa anterior se basa en el resultado de una función aleatoria y puede producir un resultado diferente.
En esta publicación, hemos discutido el algoritmo de Karger simple y hemos visto que el algoritmo no siempre produce un corte mínimo. El algoritmo anterior produce un corte mínimo con una probabilidad mayor o igual que 1/(n 2 ). Consulte la próxima publicación sobre Análisis y aplicaciones del algoritmo de Karger , se discuten las aplicaciones, la prueba de esta probabilidad y las mejoras. 

Publicación traducida automáticamente

Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *