fbpx
Wikipedia

Algoritmo de Prim

El algoritmo de Prim es un algoritmo perteneciente a la teoría de los grafos para encontrar un árbol recubridor mínimo en un grafo conexo, no dirigido y cuyas aristas están etiquetadas.

El algoritmo de Prim permite encontrar un árbol recubridor mínimo de un grafo.

En otras palabras, el algoritmo encuentra un subconjunto de aristas que forman un árbol con todos los vértices, donde el peso total de todas las aristas en el árbol es el mínimo posible. Si el grafo no es conexo, entonces el algoritmo encontrará el árbol recubridor mínimo para uno de los componentes conexos que forman dicho grafo no conexo.

El algoritmo fue diseñado en 1930 por el matemático Vojtech Jarnik y luego de manera independiente por el científico computacional Robert C. Prim en 1957 y redescubierto por Dijkstra en 1959. Por esta razón, el algoritmo es también conocido como algoritmo DJP o algoritmo de Jarnik.

Descripción

El algoritmo incrementa continuamente el tamaño de un árbol, comenzando por un vértice inicial al que se le van agregando sucesivamente vértices cuya distancia a los anteriores es mínima. Esto significa que en cada paso, las aristas a considerar son aquellas que inciden en vértices que ya pertenecen al árbol.

El árbol recubridor mínimo está completamente construido cuando no quedan más vértices por agregar.

El algoritmo podría ser informalmente descrito siguiendo los siguientes pasos:

  1. Inicializar un árbol con un único vértice, elegido arbitrariamente del grafo.
  2. Aumentar el árbol por un lado. Llamamos lado a la unión entre dos vértices: de las posibles uniones que pueden conectar el árbol a los vértices que no están aún en el árbol, encontrar el lado de menor distancia y unirlo al árbol.
  3. Repetir el paso 2 (hasta que todos los vértices pertenezcan al árbol)

Para hacerlo más en detalle, debe ser implementado el pseudocódigo siguiente.

  1. Asociar con cada vértice v del grafo un número C[v] (el mínimo coste de conexión a v) y a un lado E[v] (el lado que provee esa conexión de mínimo coste). Para inicializar esos valores, se establecen todos los valores de C[v] a +∞ (o a cualquier número más grande que el máximo tamaño de lado) y establecemos cada E[v] a un valor "flag"(bandera) que indica que no hay ningún lado que conecte v a vértices más cercanos.
  2. Inicializar un bosque vacío F y establecer Q vértices que aún no han sido incluidos en F (inicialmente, todos los vértices).
  3. Repetir los siguientes pasos hasta que Q esté vacío:
    1. Encontrar y eliminar un vértice v de Q teniendo el mínimo valor de C[v]
    2. Añadir v a F y, si E[v] no tiene el valor especial de "flag", añadir también E[v] a F
    3. Hacer un bucle sobre los lados vw conectando v a otros vértices w. Para cada lado, si w todavía pertenece a Q y vw tiene tamaño más pequeño que C[w], realizar los siguientes pasos:
      1. Establecer C[w] al coste del lado vw
      2. Establecer E[w] apuntando al lado vw
  4. Devolver F

Como se ha descrito arriba, el vértice inicial para el algoritmo será elegido arbitrariamente, porque la primera iteración del bucle principal del algoritmo tendrá un número de vértices en Q que tendrán todos el mismo tamaño, y el algoritmo empezará automáticamente un nuevo árbol en F cuando complete un árbol de expansión a partir de cada vértice conectado del grafo. El algoritmo debe ser modificado para empezar con cualquier vértice particular s para configurar C[s] para que sea un número más pequeño que los otros valores de C (por norma, cero), y debe ser modificado para solo encontrar un único árbol de expansión y no un bosque entero de expansión, parando cuando encuentre otro vértice con "flag" que no tiene ningún lado asociado.

Hay diferentes variaciones del algoritmo que difieren unas de otras en cómo implementar Q: Como una única Lista enlazada o un vector de vértices, o como una estructura de datos organizada con una cola de prioridades, más compleja. Esta elección lidera las diferencias en complejidad de tiempo del algoritmo. En general, una cola de prioridades será más rápida encontrando el vértice v con el mínimo coste, pero ello conllevará actualizaciones más costosas cuando el valor de C[w] cambie.

Pseudocódigo del algoritmo

 Prim (Grafo G) /* Inicializamos todos los nodos del grafo.  La distancia la ponemos a infinito y el padre de cada nodo a NULL Encolamos, en una cola de prioridad donde la prioridad es la distancia, todas las parejas <nodo, distancia> del grafo*/ por cada u en V[G] hacer distancia[u] = INFINITO padre[u] = NULL Añadir(cola,<u, distancia[u]>) distancia[u]=0 Actualizar(cola,<u, distancia[u]>) mientras !esta_vacia(cola) hacer // OJO: Se entiende por mayor prioridad aquel nodo cuya distancia[u] es menor. u = extraer_minimo(cola) //devuelve el mínimo y lo elimina de la cola. por cada v adyacente a 'u' hacer si ((v ∈ cola) && (distancia[v] > peso(u, v)) entonces padre[v] = u distancia[v] = peso(u, v) Actualizar(cola,<v, distancia[v]>) 

Código en Haskell (Lenguaje funcional)

--Se implementa la estructura de datos Graph (WeightedGraph).  --No existe como tal en el lenguaje. import DataStructures.Graph.WeightedGraph import Data.List(delete, minimumBy) prim :: (Ord a) => WeightedGraph a Int -> a -> WeightedGraph a Int prim graph v | elem v vs == False = error"el vertice no pertenece al grafo"  | otherwise = mkWeightedGraphEdges vs (aux graph [v] (delete v vs) [])  where  vs = vertices graph aux :: (Ord a) => WeightedGraph a Int -> [a] -> [a] -> [WeightedEdge a Int] -> [WeightedEdge a Int] aux g visited [] aristas = aristas aux g visited nvisited aristas = aux g (v:visited) (delete v nvisited) aristas'  where  aristaPosibles = [WE visitado peso avisitar | (WE visitado peso avisitar) <- weigthedEdges g, elem visitado visited, elem avisitar nvisited]  (WE c p v) = minimumBy (\(WE _ p' _) (WE _ p'' _) -> if p'<p'' then LT else GT) aristaPosibles  aristas' = (WE c p v):aristas 

Código en JAVA (Lista de Adyacencia)

// Se implementa la clase Grafo en JAVA. No existe como tal en el lenguaje. // Implementación del Algoritmo de Prim utilizando lista de adyacencia.  public class Algoritmos {  public Grafo<T> arbolExpMinPrim(Grafo<T> g, T inicio) {  // Obtengo la cantidad total de vértices  int verticesTotales = g.getVertices().size();  Vertice<T> vOrigen = g.buscarVertice(inicio);  if (vOrigen != null) {  Grafo<T> gNuevo = new Grafo<>(g.isDirigido());  g.getVertices().stream().forEach((v) -> {  gNuevo.agregarVertice(v.getContenido());  });   // Para esta implementación, los pesos son números enteros.  PriorityQueue<Arco<T>> cola = new PriorityQueue<>((Arco a1, Arco a2) -> Integer.compare(a1.getPeso(), a2.getPeso()));   int cont = 0;   while (cont < verticesTotales) {  for (Iterator<Arco> it = vOrigen.getArcos().iterator(); it.hasNext();) {  Arco<T> arc = it.next();  if (!arc.getDestino().isVisitado()) {  cola.offer(arc);  }  }   Arco<T> arco = cola.poll();  if (!arco.getDestino().isVisitado()) {  arco.getDestino().setVisitado(true);  gNuevo.agregarArco(arco.getPrevio().getContenido(), arco.getDestino().getContenido(), arco.getPeso());  cont ++;  vOrigen = arco.getDestino();  }  }  return gNuevo;   }  return null;  } } 

Código en C++

//**** Comienza Archivo grafo.h *****// #include <vector> using namespace std; class Grafo { public:  Grafo();  Grafo(int nodos);  vector< vector<int> > prim(); private:  const int INF = numeric_limits<int>::max();  int cantidadNodos; //cantidad de nodos  vector< vector<int> > adyacencia; //matriz de adyacencia }; //**** Finaliza Archivo grafo.h *****// //**** Comienza Archivo grafo.cpp *****// Grafo::Grafo() { } Grafo::Grafo(int nodos) {  this->cantidadNodos = nodos;  this->adyacencia = vector< vector<int> > (cantidadNodos);  for(int i = 0; i < cantidadNodos; i++)  adyacencia[i] = vector<int> (cantidadNodos, INF); } vector< vector<int> > Grafo :: prim(){  // uso una copia de adyacencia porque necesito eliminar columnas  vector< vector<int> > adyacencia = this->adyacencia;  vector< vector<int> > arbol(cantidadNodos);  vector<int> markedLines;  vector<int> :: iterator vectorIterator;  // Inicializo las distancias del arbol en INF.  for(int i = 0; i < cantidadNodos; i++)  arbol[i] = vector<int> (cantidadNodos, INF);  int padre = 0;  int hijo = 0;  while(markedLines.size() + 1 < cantidadNodos){  padre = hijo;  // Marco la fila y elimino la columna del nodo padre.  markedLines.push_back(padre);  for(int i = 0; i < cantidadNodos; i++)  adyacencia[i][padre] = INF;  // Encuentro la menor distancia entre las filas marcadas.  // El nodo padre es la linea marcada y el nodo hijo es la columna del minimo.  int min = INF;  for(vectorIterator = markedLines.begin(); vectorIterator != markedLines.end(); vectorIterator++)  for(int i = 0; i < cantidadNodos; i++)  if(min > adyacencia[*vectorIterator][i]){  min = adyacencia[*vectorIterator][i];  padre = *vectorIterator;  hijo = i;  }  arbol[padre][hijo] = min;  arbol[hijo][padre] = min;  }  return arbol; } //**** Finaliza Archivo grafo.cpp *****// 

Código en JAVA

//Se utiliza una clase Graph previamente implementada (no existe en Java)

public class Algorithms { public static Graph PrimsAlgorithm (Graph g, int s) { int n = g.getNumberOfVertices(); Entry[] table = new Entry [n]; for (int v = 0; v < n; ++v) table [v] = new Entry (); table [s].distance = 0; PriorityQueue queue = new BinaryHeap (g.getNumberOfEdges()); queue.enqueue ( new Association (new Int (0), g.getVertex (s))); while (!queue.isEmpty ()) { Association assoc = (Association) queue.dequeueMin(); Vertex v0 = (Vertex) assoc.getValue (); int n0 = v0.getNumber (); if (!table [n0].known) { table [n0].known = true; Enumeration p = v0.getEmanatingEdges (); while (p.hasMoreElements ()) { Edge edge = (Edge) p.nextElement (); Vertex v1 = edge.getMate (v0); int n1 = v1.getNumber (); Int wt = (Int) edge.getWeight (); int d = wt.intValue (); if (!table[n1].known && table[n1].distance>d) { table [n1].distance = d; table [n1].predecessor = n0; queue.enqueue ( new Association (new Int (d), v1)); } } } } Graph result = new GraphAsLists (n); for (int v = 0; v < n; ++v) result.addVertex (v); for (int v = 0; v < n; ++v) { if (v != s) result.addEdge (v, table [v].predecessor); } return result; } } 

Código en Python

# Implementar un clase Grafo donde los vértices es un conjunto y las aristas es un conjunto de 2-subconjuntos de vértices. # Los 2-subconjuntos se implementan con frozenset({v, w}) si v, w vértices (pues Python no admite conjuntos de conjuntos) # Las funciones y métodos son los obvios. Si G es grafo: # G.vertices(): es el conjunto de vértices # G.aristas(): es el conjunto de aristas # G.adyacentes(v): es el conjunto de vértices adyacentes a un vértice v # G.agregar_arista(e): agrega la arista e  def prim(G: Grafo , pesos):  # pre: pesos un diccionario donde las claves son las aristas y los valores son reales no negativos.   # post: devuelve mst un MST de G.   r = next(iter(G.vertices())) # toma un vértice de G sin quitarlo  clave, padre = {}, {} # dos diccionarios vacíos. El primero es una "cola de prioridad". El segundo indicará quien será el padre en el MST.  INFINITO = 2 * max(pesos.values()) # INFINITO es un valor más alto que todos los pesos  for u in G.vertices():  clave[u] = INFINITO  padre[u] = None # Cuando el algoritmo termina padre[v] será el padre de v en el MST, para los v que no son raíz (el vértice r).   clave[r] = 0  cola = G.vertices()  while cola != set({}):  u = min([[clave[v],v] for v in cola])[1] # un vértice de cola con clave[u] mínima  cola.remove(u)  for v in G.adyacentes(u):  e = frozenset({u, v})  if v in cola and pesos[e] < clave[v]:  padre[v] = u  clave[v] = pesos[e]  mst = Grafo(G.vertices(), set({})) # este va a ser el MST. Se inicializa como un grafo con todos los vértices de G y si aristas.   for v in mst.vertices() - {r}:  mst.agregar_arista(frozenset({v,padre[v]}))  return mst 

Otra versión sin usar Colas

 public int[][] AlgPrim(int[][] Matriz) { //Llega la matriz a la que le vamos a aplicar el algoritmo boolean[] marcados = new boolean[ListaVertices.size()]; //Creamos un vector booleano, para saber cuales están marcados String vertice = ListaVertices.get(0); //Le introducimos un nodo aleatorio, o el primero return AlgPrim(Matriz, marcados, vertice, new int[Matriz.length][Matriz.length]); //Llamamos al método recursivo mandándole  } //un matriz nueva para que en ella nos  //devuelva el árbol final private int[][] AlgPrim(int[][] Matriz, boolean[] marcados, String vertice, int[][] Final) { marcados[ListaVertices.indexOf(vertice)] = true;//marcamos el primer nodo int aux = -1; if (!TodosMarcados(marcados)) { //Mientras que no todos estén marcados for (int i = 0; i < marcados.length; i++) { //Recorremos sólo las filas de los nodos marcados if (marcados[i]) { for (int j = 0; j < Matriz.length; j++) { if (Matriz[i][j] != 0) { //Si la arista existe if (!marcados[j]) { //Si el nodo no ha sido marcado antes if (aux == -1) { //Esto sólo se hace una vez aux = Matriz[i][j]; } else { aux = Math.min(aux, Matriz[i][j]); //Encontramos la arista mínima } } } } } } //Aquí buscamos el nodo correspondiente a esa arista mínima (aux) for (int i = 0; i < marcados.length; i++) { if (marcados[i]) { for (int j = 0; j < Matriz.length; j++) { if (Matriz[i][j] == aux) { if (!marcados[j]) { //Si no ha sido marcado antes Final[i][j] = aux; //Se llena la matriz final con el valor Final[j][i] = aux;//Se llena la matriz final con el valor return AlgPrim(Matriz, marcados, ListaVertices.get(j), Final); //se llama de nuevo al método con //el nodo a marcar } } } } } } return Final; } public boolean TodosMarcados(boolean[] vertice) { //Método para saber si todos están marcados for (boolean b : vertice) { if (!b) { return b; } } return true; } 

Demostración

Sea   un grafo conexo y ponderado.

En toda iteración del algoritmo de Prim, se debe encontrar una arista que conecte un nodo del subgrafo a otro nodo fuera del subgrafo.

Ya que   es conexo, siempre habrá un camino para todo nodo.

La salida   del algoritmo de Prim es un árbol porque las aristas y los nodos agregados a   están conectados.

Sea   el árbol recubridor mínimo de  .

Si   es el árbol recubridor mínimo.

Si no, sea   la primera arista agregada durante la construcción de  , que no está en   y sea   el conjunto de nodos conectados por las aristas agregadas antes que  . Entonces un extremo de   está en   y el otro no. Ya que   es el árbol recubridor mínimo de   hay un camino en   que une los dos extremos. Mientras que uno se mueve por el camino, se debe encontrar una arista   uniendo un nodo en   a uno que no está en  . En la iteración que   se agrega a  ,   también se podría haber agregado y se hubiese agregado en vez de   si su peso fuera menor que el de  . Ya que   no se agregó se concluye:

 

Sea   el grafo obtenido al remover   y agregando  . Es fácil mostrar que   conexo tiene la misma cantidad de aristas que  , y el peso total de sus aristas no es mayor que el de  , entonces también es un árbol recubridor mínimo de   y contiene a   y todas las aristas agregadas anteriormente durante la construcción de  . Si se repiten los pasos mencionados anteriormente, eventualmente se obtendrá el árbol recubridor mínimo de   que es igual a  .

Esto demuestra que   es el árbol recubridor mínimo de  .

Ejemplo de ejecución del algoritmo

Imagen Descripción No visto En el grafo En el árbol
  Este es el grafo ponderado de partida. No es un árbol, ya que para serlo se requiere que no haya ciclos, y en este caso sí hay. Los números cerca de las aristas indican el peso. Ninguna de las aristas está marcada, y el vértice D ha sido elegido arbitrariamente como el punto de partida. C, G A, B, E, F D
  El segundo vértice es el más cercano a D: A está a 5 de distancia, B a 9, E a 15 y F a 6. De estos, 5 es el valor más pequeño, así que marcamos la arista DA. C, G B, E, F A, D
  El próximo vértice a elegir es el más cercano a D o A. B está a 9 de distancia de D y a 7 de A, E está a 15, y F está a 6. 6 es el valor más pequeño, así que marcamos el vértice F y a la arista DF. C B, E, G A, D, F
  El algoritmo continua. El vértice B, que está a una distancia de 7 de A, es el siguiente marcado. En este punto la arista DB es marcada en rojo porque sus dos extremos ya están en el árbol y por lo tanto no podrá ser utilizado. null C, E, G A, D, F, B
  Aquí hay que elegir entre C, E y G. C está a 8 de distancia de B, E está a 7 de distancia de B, y G está a 11 de distancia de F. E está más cerca, entonces marcamos el vértice E y la arista EB. Otras dos aristas fueron marcadas en rojo porque ambos vértices que unen fueron agregados al árbol. null C, G A, D, F, B, E
  Solo quedan disponibles C y G. C está a 5 de distancia de E, y G a 9 de distancia de E. Se elige C, y se marca con el arco EC. El arco BC también se marca con rojo. null G A, D, F, B, E, C
  G es el único vértice pendiente, y está más cerca de E que de F, así que se agrega EG al árbol. Todos los vértices están ya marcados, el árbol de expansión mínimo se muestra en verde. En este caso con un peso de 39. null null A, D, F, B, E, C, G

Referencias

Enlaces externos

  • por Kenji Ikeda, Ph.D
  • Create and Solve Mazes by Kruskal's and Prim's algorithms
  • Animated example of Prim's algorithm
  • Ejemplo interactivo en español(Java Applet) (enlace roto disponible en Internet Archive; véase el historial, la primera versión y la última).
  • Prim's algorithm code
  •   Datos: Q470813
  •   Multimedia: Prim's algorithm

algoritmo, prim, algoritmo, prim, algoritmo, perteneciente, teoría, grafos, para, encontrar, árbol, recubridor, mínimo, grafo, conexo, dirigido, cuyas, aristas, están, etiquetadas, algoritmo, prim, permite, encontrar, árbol, recubridor, mínimo, grafo, otras, p. El algoritmo de Prim es un algoritmo perteneciente a la teoria de los grafos para encontrar un arbol recubridor minimo en un grafo conexo no dirigido y cuyas aristas estan etiquetadas El algoritmo de Prim permite encontrar un arbol recubridor minimo de un grafo En otras palabras el algoritmo encuentra un subconjunto de aristas que forman un arbol con todos los vertices donde el peso total de todas las aristas en el arbol es el minimo posible Si el grafo no es conexo entonces el algoritmo encontrara el arbol recubridor minimo para uno de los componentes conexos que forman dicho grafo no conexo El algoritmo fue disenado en 1930 por el matematico Vojtech Jarnik y luego de manera independiente por el cientifico computacional Robert C Prim en 1957 y redescubierto por Dijkstra en 1959 Por esta razon el algoritmo es tambien conocido como algoritmo DJP o algoritmo de Jarnik Indice 1 Descripcion 2 Pseudocodigo del algoritmo 3 Codigo en Haskell Lenguaje funcional 4 Codigo en JAVA Lista de Adyacencia 5 Codigo en C 6 Codigo en JAVA 7 Codigo en Python 8 Otra version sin usar Colas 9 Demostracion 10 Ejemplo de ejecucion del algoritmo 11 Referencias 12 Enlaces externosDescripcion EditarEl algoritmo incrementa continuamente el tamano de un arbol comenzando por un vertice inicial al que se le van agregando sucesivamente vertices cuya distancia a los anteriores es minima Esto significa que en cada paso las aristas a considerar son aquellas que inciden en vertices que ya pertenecen al arbol El arbol recubridor minimo esta completamente construido cuando no quedan mas vertices por agregar El algoritmo podria ser informalmente descrito siguiendo los siguientes pasos Inicializar un arbol con un unico vertice elegido arbitrariamente del grafo Aumentar el arbol por un lado Llamamos lado a la union entre dos vertices de las posibles uniones que pueden conectar el arbol a los vertices que no estan aun en el arbol encontrar el lado de menor distancia y unirlo al arbol Repetir el paso 2 hasta que todos los vertices pertenezcan al arbol Para hacerlo mas en detalle debe ser implementado el pseudocodigo siguiente Asociar con cada vertice v del grafo un numero C v el minimo coste de conexion a v y a un lado E v el lado que provee esa conexion de minimo coste Para inicializar esos valores se establecen todos los valores de C v a o a cualquier numero mas grande que el maximo tamano de lado y establecemos cada E v a un valor flag bandera que indica que no hay ningun lado que conecte v a vertices mas cercanos Inicializar un bosque vacio F y establecer Q vertices que aun no han sido incluidos en F inicialmente todos los vertices Repetir los siguientes pasos hasta que Q este vacio Encontrar y eliminar un vertice v de Q teniendo el minimo valor de C v Anadir v a F y si E v no tiene el valor especial de flag anadir tambien E v a F Hacer un bucle sobre los lados vw conectando v a otros vertices w Para cada lado si w todavia pertenece a Q y vw tiene tamano mas pequeno que C w realizar los siguientes pasos Establecer C w al coste del lado vw Establecer E w apuntando al lado vw Devolver FComo se ha descrito arriba el vertice inicial para el algoritmo sera elegido arbitrariamente porque la primera iteracion del bucle principal del algoritmo tendra un numero de vertices en Q que tendran todos el mismo tamano y el algoritmo empezara automaticamente un nuevo arbol en F cuando complete un arbol de expansion a partir de cada vertice conectado del grafo El algoritmo debe ser modificado para empezar con cualquier vertice particular s para configurar C s para que sea un numero mas pequeno que los otros valores de C por norma cero y debe ser modificado para solo encontrar un unico arbol de expansion y no un bosque entero de expansion parando cuando encuentre otro vertice con flag que no tiene ningun lado asociado Hay diferentes variaciones del algoritmo que difieren unas de otras en como implementar Q Como una unica Lista enlazada o un vector de vertices o como una estructura de datos organizada con una cola de prioridades mas compleja Esta eleccion lidera las diferencias en complejidad de tiempo del algoritmo En general una cola de prioridades sera mas rapida encontrando el vertice v con el minimo coste pero ello conllevara actualizaciones mas costosas cuando el valor de C w cambie Pseudocodigo del algoritmo EditarEstructura de datos auxiliar Cola de prioridad se puede implementar con un heap Prim Grafo G Inicializamos todos los nodos del grafo La distancia la ponemos a infinito y el padre de cada nodo a NULL Encolamos en una cola de prioridad donde la prioridad es la distancia todas las parejas lt nodo distancia gt del grafo por cada u en V G hacer distancia u INFINITO padre u NULL Anadir cola lt u distancia u gt distancia u 0 Actualizar cola lt u distancia u gt mientras esta vacia cola hacer OJO Se entiende por mayor prioridad aquel nodo cuya distancia u es menor u extraer minimo cola devuelve el minimo y lo elimina de la cola por cada v adyacente a u hacer si v cola amp amp distancia v gt peso u v entonces padre v u distancia v peso u v Actualizar cola lt v distancia v gt Codigo en Haskell Lenguaje funcional Editar Se implementa la estructura de datos Graph WeightedGraph No existe como tal en el lenguaje import DataStructures Graph WeightedGraph import Data List delete minimumBy prim Ord a gt WeightedGraph a Int gt a gt WeightedGraph a Int prim graph v elem v vs False error el vertice no pertenece al grafo otherwise mkWeightedGraphEdges vs aux graph v delete v vs where vs vertices graph aux Ord a gt WeightedGraph a Int gt a gt a gt WeightedEdge a Int gt WeightedEdge a Int aux g visited aristas aristas aux g visited nvisited aristas aux g v visited delete v nvisited aristas where aristaPosibles WE visitado peso avisitar WE visitado peso avisitar lt weigthedEdges g elem visitado visited elem avisitar nvisited WE c p v minimumBy WE p WE p gt if p lt p then LT else GT aristaPosibles aristas WE c p v aristasCodigo en JAVA Lista de Adyacencia Editar Se implementa la clase Grafo en JAVA No existe como tal en el lenguaje Implementacion del Algoritmo de Prim utilizando lista de adyacencia public class Algoritmos public Grafo lt T gt arbolExpMinPrim Grafo lt T gt g T inicio Obtengo la cantidad total de vertices int verticesTotales g getVertices size Vertice lt T gt vOrigen g buscarVertice inicio if vOrigen null Grafo lt T gt gNuevo new Grafo lt gt g isDirigido g getVertices stream forEach v gt gNuevo agregarVertice v getContenido Para esta implementacion los pesos son numeros enteros PriorityQueue lt Arco lt T gt gt cola new PriorityQueue lt gt Arco a1 Arco a2 gt Integer compare a1 getPeso a2 getPeso int cont 0 while cont lt verticesTotales for Iterator lt Arco gt it vOrigen getArcos iterator it hasNext Arco lt T gt arc it next if arc getDestino isVisitado cola offer arc Arco lt T gt arco cola poll if arco getDestino isVisitado arco getDestino setVisitado true gNuevo agregarArco arco getPrevio getContenido arco getDestino getContenido arco getPeso cont vOrigen arco getDestino return gNuevo return null Codigo en C Editar Comienza Archivo grafo h include lt vector gt using namespace std class Grafo public Grafo Grafo int nodos vector lt vector lt int gt gt prim private const int INF numeric limits lt int gt max int cantidadNodos cantidad de nodos vector lt vector lt int gt gt adyacencia matriz de adyacencia Finaliza Archivo grafo h Comienza Archivo grafo cpp Grafo Grafo Grafo Grafo int nodos this gt cantidadNodos nodos this gt adyacencia vector lt vector lt int gt gt cantidadNodos for int i 0 i lt cantidadNodos i adyacencia i vector lt int gt cantidadNodos INF vector lt vector lt int gt gt Grafo prim uso una copia de adyacencia porque necesito eliminar columnas vector lt vector lt int gt gt adyacencia this gt adyacencia vector lt vector lt int gt gt arbol cantidadNodos vector lt int gt markedLines vector lt int gt iterator vectorIterator Inicializo las distancias del arbol en INF for int i 0 i lt cantidadNodos i arbol i vector lt int gt cantidadNodos INF int padre 0 int hijo 0 while markedLines size 1 lt cantidadNodos padre hijo Marco la fila y elimino la columna del nodo padre markedLines push back padre for int i 0 i lt cantidadNodos i adyacencia i padre INF Encuentro la menor distancia entre las filas marcadas El nodo padre es la linea marcada y el nodo hijo es la columna del minimo int min INF for vectorIterator markedLines begin vectorIterator markedLines end vectorIterator for int i 0 i lt cantidadNodos i if min gt adyacencia vectorIterator i min adyacencia vectorIterator i padre vectorIterator hijo i arbol padre hijo min arbol hijo padre min return arbol Finaliza Archivo grafo cpp Codigo en JAVA Editar Se utiliza una clase Graph previamente implementada no existe en Java public class Algorithms public static Graph PrimsAlgorithm Graph g int s int n g getNumberOfVertices Entry table new Entry n for int v 0 v lt n v table v new Entry table s distance 0 PriorityQueue queue new BinaryHeap g getNumberOfEdges queue enqueue new Association new Int 0 g getVertex s while queue isEmpty Association assoc Association queue dequeueMin Vertex v0 Vertex assoc getValue int n0 v0 getNumber if table n0 known table n0 known true Enumeration p v0 getEmanatingEdges while p hasMoreElements Edge edge Edge p nextElement Vertex v1 edge getMate v0 int n1 v1 getNumber Int wt Int edge getWeight int d wt intValue if table n1 known amp amp table n1 distance gt d table n1 distance d table n1 predecessor n0 queue enqueue new Association new Int d v1 Graph result new GraphAsLists n for int v 0 v lt n v result addVertex v for int v 0 v lt n v if v s result addEdge v table v predecessor return result Codigo en Python Editar Implementar un clase Grafo donde los vertices es un conjunto y las aristas es un conjunto de 2 subconjuntos de vertices Los 2 subconjuntos se implementan con frozenset v w si v w vertices pues Python no admite conjuntos de conjuntos Las funciones y metodos son los obvios Si G es grafo G vertices es el conjunto de vertices G aristas es el conjunto de aristas G adyacentes v es el conjunto de vertices adyacentes a un vertice v G agregar arista e agrega la arista e def prim G Grafo pesos pre pesos un diccionario donde las claves son las aristas y los valores son reales no negativos post devuelve mst un MST de G r next iter G vertices toma un vertice de G sin quitarlo clave padre dos diccionarios vacios El primero es una cola de prioridad El segundo indicara quien sera el padre en el MST INFINITO 2 max pesos values INFINITO es un valor mas alto que todos los pesos for u in G vertices clave u INFINITO padre u None Cuando el algoritmo termina padre v sera el padre de v en el MST para los v que no son raiz el vertice r clave r 0 cola G vertices while cola set u min clave v v for v in cola 1 un vertice de cola con clave u minima cola remove u for v in G adyacentes u e frozenset u v if v in cola and pesos e lt clave v padre v u clave v pesos e mst Grafo G vertices set este va a ser el MST Se inicializa como un grafo con todos los vertices de G y si aristas for v in mst vertices r mst agregar arista frozenset v padre v return mstOtra version sin usar Colas Editarpublic int AlgPrim int Matriz Llega la matriz a la que le vamos a aplicar el algoritmo boolean marcados new boolean ListaVertices size Creamos un vector booleano para saber cuales estan marcados String vertice ListaVertices get 0 Le introducimos un nodo aleatorio o el primero return AlgPrim Matriz marcados vertice new int Matriz length Matriz length Llamamos al metodo recursivo mandandole un matriz nueva para que en ella nos devuelva el arbol final private int AlgPrim int Matriz boolean marcados String vertice int Final marcados ListaVertices indexOf vertice true marcamos el primer nodo int aux 1 if TodosMarcados marcados Mientras que no todos esten marcados for int i 0 i lt marcados length i Recorremos solo las filas de los nodos marcados if marcados i for int j 0 j lt Matriz length j if Matriz i j 0 Si la arista existe if marcados j Si el nodo no ha sido marcado antes if aux 1 Esto solo se hace una vez aux Matriz i j else aux Math min aux Matriz i j Encontramos la arista minima Aqui buscamos el nodo correspondiente a esa arista minima aux for int i 0 i lt marcados length i if marcados i for int j 0 j lt Matriz length j if Matriz i j aux if marcados j Si no ha sido marcado antes Final i j aux Se llena la matriz final con el valor Final j i aux Se llena la matriz final con el valor return AlgPrim Matriz marcados ListaVertices get j Final se llama de nuevo al metodo con el nodo a marcar return Final public boolean TodosMarcados boolean vertice Metodo para saber si todos estan marcados for boolean b vertice if b return b return true Demostracion EditarSea G displaystyle G un grafo conexo y ponderado En toda iteracion del algoritmo de Prim se debe encontrar una arista que conecte un nodo del subgrafo a otro nodo fuera del subgrafo Ya que G displaystyle G es conexo siempre habra un camino para todo nodo La salida Y displaystyle Y del algoritmo de Prim es un arbol porque las aristas y los nodos agregados a Y displaystyle Y estan conectados Sea Y 1 displaystyle Y 1 el arbol recubridor minimo de G displaystyle G Si Y 1 Y Y displaystyle Y 1 Y Rightarrow Y es el arbol recubridor minimo Si no sea e displaystyle e la primera arista agregada durante la construccion de Y displaystyle Y que no esta en Y 1 displaystyle Y 1 y sea V displaystyle V el conjunto de nodos conectados por las aristas agregadas antes que e displaystyle e Entonces un extremo de e displaystyle e esta en V displaystyle V y el otro no Ya que Y 1 displaystyle Y 1 es el arbol recubridor minimo de G displaystyle G hay un camino en Y 1 displaystyle Y 1 que une los dos extremos Mientras que uno se mueve por el camino se debe encontrar una arista f displaystyle f uniendo un nodo en V displaystyle V a uno que no esta en V displaystyle V En la iteracion que e displaystyle e se agrega a Y displaystyle Y f displaystyle f tambien se podria haber agregado y se hubiese agregado en vez de e displaystyle e si su peso fuera menor que el de e displaystyle e Ya que f displaystyle f no se agrego se concluye P f P e displaystyle P f geq P e Sea Y 2 displaystyle Y 2 el grafo obtenido al remover f displaystyle f y agregando e Y 1 displaystyle e in Y 1 Es facil mostrar que Y 2 displaystyle Y 2 conexo tiene la misma cantidad de aristas que Y 1 displaystyle Y 1 y el peso total de sus aristas no es mayor que el de Y 1 displaystyle Y 1 entonces tambien es un arbol recubridor minimo de G displaystyle G y contiene a e displaystyle e y todas las aristas agregadas anteriormente durante la construccion de V displaystyle V Si se repiten los pasos mencionados anteriormente eventualmente se obtendra el arbol recubridor minimo de G displaystyle G que es igual a Y displaystyle Y Esto demuestra que Y displaystyle Y es el arbol recubridor minimo de G displaystyle G Ejemplo de ejecucion del algoritmo EditarImagen Descripcion No visto En el grafo En el arbol Este es el grafo ponderado de partida No es un arbol ya que para serlo se requiere que no haya ciclos y en este caso si hay Los numeros cerca de las aristas indican el peso Ninguna de las aristas esta marcada y el vertice D ha sido elegido arbitrariamente como el punto de partida C G A B E F D El segundo vertice es el mas cercano a D A esta a 5 de distancia B a 9 E a 15 y F a 6 De estos 5 es el valor mas pequeno asi que marcamos la arista DA C G B E F A D El proximo vertice a elegir es el mas cercano a D o A B esta a 9 de distancia de D y a 7 de A E esta a 15 y F esta a 6 6 es el valor mas pequeno asi que marcamos el vertice F y a la arista DF C B E G A D F El algoritmo continua El vertice B que esta a una distancia de 7 de A es el siguiente marcado En este punto la arista DB es marcada en rojo porque sus dos extremos ya estan en el arbol y por lo tanto no podra ser utilizado null C E G A D F B Aqui hay que elegir entre C E y G C esta a 8 de distancia de B E esta a 7 de distancia de B y G esta a 11 de distancia de F E esta mas cerca entonces marcamos el vertice E y la arista EB Otras dos aristas fueron marcadas en rojo porque ambos vertices que unen fueron agregados al arbol null C G A D F B E Solo quedan disponibles C y G C esta a 5 de distancia de E y G a 9 de distancia de E Se elige C y se marca con el arco EC El arco BC tambien se marca con rojo null G A D F B E C G es el unico vertice pendiente y esta mas cerca de E que de F asi que se agrega EG al arbol Todos los vertices estan ya marcados el arbol de expansion minimo se muestra en verde En este caso con un peso de 39 null null A D F B E C GReferencias EditarR C Prim Shortest connection networks and some generalisations In Bell System Technical Journal 36 1957 pp 1389 1401 D Cherition and R E Tarjan Finding minimum spanning trees In SIAM Journal of Computing 5 Dec 1976 pp 724 741 Thomas H Cormen Charles E Leiserson Ronald L Rivest and Clifford Stein Introduction to Algorithms Second Edition MIT Press and McGraw Hill 2001 ISBN 0 262 03293 7 Section 23 2 The algorithms of Kruskal and Prim pp 567 574 Enlaces externos EditarEjemplos usando JAVA incluyen codigo por Kenji Ikeda Ph D Create and Solve Mazes by Kruskal s and Prim s algorithms Animated example of Prim s algorithm Ejemplo interactivo Java Applet Ejemplo interactivo en espanol Java Applet enlace roto disponible en Internet Archive vease el historial la primera version y la ultima Prim s algorithm code Datos Q470813 Multimedia Prim s algorithm Obtenido de https es wikipedia org w index php title Algoritmo de Prim amp oldid 139719907, wikipedia, wiki, leyendo, leer, libro, biblioteca,

español

, española, descargar, gratis, descargar gratis, mp3, video, mp4, 3gp, jpg, jpeg, gif, png, imagen, música, canción, película, libro, juego, juegos