Está en la página 1de 21

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.
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.

Índice
  [ocultar] 

 1Descripción conceptual
 2Pseudocódigo del algoritmo
 3Código en Haskell (Lenguaje funcional)
 4Código en JAVA (Lista de Adyacencia)
 5Código en C++
 6Código en JAVA
 7Otra versión sin usar Colas
 8Demostración
 9Ejemplo de ejecución del algoritmo
 10Referencias
 11Enlaces externos

Descripción conceptual[editar]
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.

Pseudocódigo del algoritmo[editar]


 Estructura 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 <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
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) && (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)[editar]

1 --Se implementa la estructura de datos Graph (WeightedGraph).


2 --No existe como tal en el lenguaje.
3 import DataStructures.Graph.WeightedGraph
4 import Data.List(delete, minimumBy)
5 prim :: (Ord a) => WeightedGraph a Int -> a -> WeightedGraph a Int
6 prim graph v | elem v vs == False = error"el vertice no pertenece
al grafo"
7 | otherwise = mkWeightedGraphEdges vs (aux graph [v]
(delete v vs) [])
8 where
9 vs = vertices graph
10 aux :: (Ord a) => WeightedGraph a Int -> [a] -> [a] ->
[WeightedEdge a Int] -> [WeightedEdge a Int]
11 aux g visited [] aristas = aristas
12 aux g visited nvisited aristas = aux g (v:visited) (delete v
nvisited) aristas'
13 where
14 aristaPosibles = [WE visitado peso avisitar | (WE visitado peso
avisitar) <- weigthedEdges g, elem visitado visited, elem avisitar
nvisited]
15 (WE c p v) = minimumBy (\(WE _ p' _) (WE _ p'' _) -> if p'<p''
then LT else GT) aristaPosibles
16 aristas' = (WE c p v):aristas
Código en JAVA (Lista de Adyacencia)[editar]

1 // Se implementa la clase Grafo en JAVA. No existe como tal en el


lenguaje.
2 // Implementación del Algoritmo de Prim utilizando lista de
adyacencia.
3
4 public class Algoritmos {
5 public Grafo<T> arbolExpMinPrim(Grafo<T> g, T inicio) {
6 // Obtengo la cantidad total de vértices
7 int verticesTotales = g.getVertices().size();
8 Vertice<T> vOrigen = g.buscarVertice(inicio);
9 if (vOrigen != null) {
10 Grafo<T> gNuevo = new Grafo<>(g.isDirigido());
11 g.getVertices().stream().forEach((v) -> {
12 gNuevo.agregarVertice(v.getContenido());
13 });
14
15 // Para esta implementación, los pesos son números
enteros.
16 PriorityQueue<Arco<T>> cola = new PriorityQueue<>((Arco
a1, Arco a2) -> Integer.compare(a1.getPeso(), a2.getPeso()));
17
18 int cont = 0;
19
20 while (cont < verticesTotales) {
21 for (Iterator<Arco> it =
vOrigen.getArcos().iterator(); it.hasNext();) {
22 Arco<T> arc = it.next();
23 if (!arc.getDestino().isVisitado()) {
24 cola.offer(arc);
25 }
26 }
27
28 Arco<T> arco = cola.poll();
29 if (!arco.getDestino().isVisitado()) {
30 arco.getDestino().setVisitado(true);
31
gNuevo.agregarArco(arco.getPrevio().getContenido(),
arco.getDestino().getContenido(), arco.getPeso());
32 cont ++;
33 vOrigen = arco.getDestino();
34 }
35 }
36 return gNuevo;
37
38 }
39 return null;
40 }
41 }

Código en C++[editar]

//**** Comienza Archivo grafo.h *****//


#include <vector>

using namespace std;


class Grafo
{
public:
Grafo();
Grafo(int nodos);
vector< vector<int> > prim();
private:
const int INF = -1;
int cn; //cantidad de nodos
vector< vector<int> > ady; //matriz de adyacencia
};

//**** Finaliza Archivo grafo.h *****//

//**** Comienza Archivo grafo.cpp *****//

Grafo::Grafo()
{

Grafo::Grafo(int nodos)
{
this->cn = nodos;
this->ady = vector< vector<int> > (cn);

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


ady[i] = vector<int> (cn, INF);
}

vector< vector<int> > Grafo :: prim(){


// uso una copia de ady porque necesito eliminar columnas
vector< vector<int> > adyacencia = this->ady;
vector< vector<int> > arbol(cn);
vector<int> markedLines;
vector<int> :: iterator itVec;

// Inicializo las distancias del arbol en INF.


for(int i = 0; i < cn; i++)
arbol[i] = vector<int> (cn, INF);

int padre = 0;
int hijo = 0;
while(markedLines.size() + 1 < cn){
padre = hijo;
// Marco la fila y elimino la columna del nodo padre.
markedLines.push_back(padre);
for(int i = 0; i < cn; 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(itVec = markedLines.begin(); itVec != markedLines.end();
itVec++)
for(int i = 0; i < cn; i++)
if(min > adyacencia[*itVec][i]){
min = adyacencia[*itVec][i];
padre = *itVec;
hijo = i;
}

arbol[padre][hijo] = min;
arbol[hijo][padre] = min;
}
return arbol;
}

//**** Finaliza Archivo grafo.cpp *****//


Código 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 < 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;
}
}

Otra versión sin usar Colas[editar]

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[editar]
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[editar]


No En el En el
Image Descripción
visto grafo á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 A, B,
C, G D
aristas indican el peso. Ninguna E, F
de las aristas está marcada, y el
vértice D ha sido elegido
arbitrariamente como el punto de
partida.
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. B, E,
C, G A, D
De estos, 5 es el valor más F
pequeño, así que marcamos la
arista DA.

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
B, E, A, D,
de A, E está a 15, y F está a 6. 6 C
G F
es el valor más pequeño, así que
marcamos el vértice F y a la
arista DF.

El algoritmo continua. El
vértice B, que está a una
distancia de 7 de A, es el
siguiente marcado. En este punto C, E, A, D,
null
la arista DB es marcada en rojo G F, B
porque sus dos extremos ya
están en el árbol y por lo tanto
no podrá ser utilizado.

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
A, D,
distancia de F. E está más cerca,
null C, G F, B,
entonces marcamos el
E
vértice E y la arista EB. Otras
dos aristas fueron marcadas en
rojo porque ambos vértices que
unen fueron agregados al árbol.

Sólo quedan
disponibles C y G. C está a 5 de
distancia de E, y G a 9 de A, D,
distancia de E. Se elige C, y se null G F, B,
marca con el arco EC. El E, C
arco BC también se marca con
rojo.
G es el único vértice pendiente,
y está más cerca de E que de F,
A, D,
así que se agrega EG al árbol.
F, B,
Todos los vértices están ya null null
E, C,
marcados, el árbol de expansión
G
mínimo se muestra en verde. En
este caso con un peso de 39.

PRESENTACION
La utilidad académica de una monografía nunca está de más, el uso de esta es una gran ayuda para
estudiantes en este caso universitarios es por eso que con esta recopilación de fuentes científicas
impresas mas las conclusiones llegadas al tomar opinión de varios profesionales del área hacen de
esta monografía consistente en "el algoritmo de Prim" una fuente de información más para fines
académicos.
En estos tiempos el estudiantado opta por recurrir a fuentes sin sustento científico como el internet o
simplemente dar por hecho algún comentario sin sustentación, ya sea con fines de curiosidad o
estudiantes trabajando en algún proyecto. El uso de los libros se está perdiendo y con ello los libros
mismos.
En esta monografía tocaremos el tema principal que es "El Algoritmo de Prim", dando a conocer y a
repasar algunos puntos importantes en el área, como son los grafos, los arboles, y los diferentes tipos de
términos que se usan en la teoría de grafos, también veremos cómo influye tal algoritmo en la vida
cotidiana y cuan útil nos es…

INTRODUCCION
El hombre siempre ha tenido la necesidad de recorrer muchos lugares, utilizando caminos estratégicos y
cortos buscando hallar la ruta optima con el mayor ahorro de tiempo, energía, distancia, etc. recorriendo
todos los puntos designados.
En la actualidad podemos apreciar muchas cosas que nos pueden parecer de lo más habitual, caminos,
líneas de comunicación telefónica, televisión por cable, el transporte ferroviario, líneas
aéreas, circuitos eléctricos de nuestras casas, automóviles, etc. ; lo que no pensamos frecuentemente es
que estos forman parte de algo que en matemáticas se denomina como grafos.
En esta monografía se explicara el Algoritmo de Prim, buscando aplicarlo en problemas reales y
cotidianos, utilizando en general la Teoría de Grafos.

RESUMEN
Un grafo o grafica es un conjunto finito de nodos o vértices conectados a través de aristas, los cuales
pueden ser conexos, es decir existe algún enlace con cada nodo a través de algún camino formando así
un grafo entero; O los grafos no conexos, que tienen la particularidad de que un segmento de grafo no
este enlazado a través de algún vértice al grafo principal. En la teoría de grafos existen grafos dirigidos y
grafos no dirigidos , lo grafos dirigidos son aquellos donde sus aristas tienen un sentido , quiere decir que
tienen un principio especifico en algún nodo y un destino en algún otro a diferencia de los no dirigidos que
son solo grafos simples (puede tomar ambas direcciones).
Arboles, un árbol es un grafo que no contiene ciclos y que conecta todos los nodos utilizando el menor
número de aristas posibles.
Árbol recubridor mínimo, dentro de un grafo se tiene que cubrir todos los nodos formando un árbol (sub
grafo) y utilizando el menor coste posible (menor costo, tiempo, distancia, precio, etc.)
El algoritmo de Prim es un algoritmo de la teoría de grafos que encuentra un árbol de expansión mínima
para un grafo ponderado conexo. Esto significa que se encuentra un subconjunto de las aristas que forma
un árbol que incluye todos los nodos, donde el total peso de todas las aristas en el árbol se reduce al
mínimo.  Si el gráfico no está conectado, entonces sólo se encuentra un mínimo  árbol de expansión para
uno de los componentes conectados
ABSTRACT A graph or chart is a finite set of nodes or vertices connected by edges, which can be related,
ie there is a link to each node through some path thus forming a whole graph, or graphs are not related to
are unique in that a segment of the graph is not bound by a vertex to the main graph. In graph theory there
are directed graphs and undirected graphs, the directed graphs are where its edges have a sense, means
they have a specific principle in a node and a destination unlike any other non-target are only simple
graphs (can take both directions.)  Trees, a tree is a graph that contains no cycles and connecting all the
nodes using the fewest possible edges.
Minimum spanning tree within a graph has to cover all the nodes forming a tree (sub graph) and using the
lowest possible cost (less cost, time, distance, price, etc) Prim's algorithm is an algorithm of graph theory
that finds a minimum spanning tree related to a weighted graph. This means that there is a subset of
edges forms a tree with all nodes, where the total weight of all edges in the tree is minimized. If the graph
is not connected, then it is only a minimum spanning tree for a connected component

PROLOGO
Mediante esta monografía tenemos como objetivo principal que los lectores cuenten en forma integra con
los alcances más relevantes del Algoritmo de Prim considerando la teoría de grafos teniendo en cuenta
que el estudio de los diferentes tipos de algoritmos cada vez tiene más importancia en la medida que
avanza la era de las computadoras, caminos, líneas de comunicación telefónica, televisión por cable,
el transporte ferroviario, líneas aéreas, circuitos eléctricos de nuestras casas, automóviles Y que se puede
resolver diferentes tipos de problemas utilizando dicho algoritmo. Teniendo la ventaja de ahorrar tiempo
y costos al resolver un problema determinado.
El trabajo, ha sido elaborado siguiendo una metodología dinámica, propia del grupo, lo cual garantiza a
nuestros lectores un ágil manejo y acceso a la información que desee consultar.
CAPITULO I

CONCEPTOS PREVIOS
 Grafos.
ELIAS MICHA (2003)[1], En su libro Matemáticas Discretas este autor:
"Un grafo es un conjunto no vacio de objetos llamados vértices y de un conjunto de parejas no ordenadas
de vértices llamadas Aristas."
SEYMOUR LIPSCHUTZ – MARC LIPSON (2007)[2], En su libro Matemáticas Discretas Indica:
"Un grafo tiene un numero finito de vértices y de aristas."
BERNARD KOLMAN – ROBERT C. BUSBY – SHARON ROSS (1995)[3], En su
libro Estructuras Matemáticas Discretas nos dice:
"Un grafo G consta de un conjunto V de objetos llamados vértices, un conjunto finito E de objetos
llamados aristas y una función "y" que asigna a cada arista un subconjunto {v, w}, donde "v, w" son
vértices (que podrían ser iguales)."
 Conectividad

ELIAS MICHA (2003), ""Un Grafo es conexo si consiste de una sola pieza. Es decir que los vértices están
unidos a través de aristas."
SEYMOUR LIPSCHUTZ – MARC LIPSON (2007), "Un Grafo de conectividad consta de una secuencia
alternada de vértices y aristas de la forma donde cada arista contiene a los vértices."
Por lo tanto concluimos que la conectividad de un grafo es el enlace que puede tener 2 nodos a travez
de uno o más aristas.
 Grafos Dirigidos y no dirigidos.

JIRÍ MATOUŠEK, JAROSLAV NEŠETRIL(2008) [4]En su libro Invitation to Discrete Mathematics nos


dice:
"Un grafo dirigido G es un par (V,E), donde E es un subconjunto del producto cartesiano VxV. A los pares
ordenados(x,y) ? E se les llama ramas dirigidas. Decimos que una rama dirigida e=(x,y) tiene origen x y
por final y, o también decimos que es una rama de x a y."
ROBERT SEDGEWICK (1992) [5]En su libro Algoritmos en C++ nos dice.
" Un grafo no dirigido, la conectividad simple proporciona los vértices que pueden ser alcanzados desde
un vértice dado recorriendo los aristas del grafo."

 Arboles.
Es un grafo que no tiene ciclos y que conecta a todos los puntos,. En un grafo con n vértices,
los árboles tienen exactamente n - 1 aristas, y hay nn-2 árboles posibles. Su importancia radica en que los
árboles son grafos que conectan todos los vértices utilizando el menor número posible de aristas.
 Árbol Recubridor Mínimo.
BERNARD KOLMAN – ROBERT C. BUSBY – SHARON ROSS (1995)[6], En su libro Estructuras
Matemáticas Discretas para la computación señala:
"Dado un grafo conexo, un árbol recubridor mínimo de ese grafo es un subgrafo que tiene que ser
un árbol y contener todos los vértices del grafo inicial. Cada arista tiene asignado un peso proporcional
entre ellos, que es un número representativo de algún objeto, distancia, etc., y se usa para asignar un
peso total al árbol recubridor mínimo computando la suma de todos los pesos de las aristas del árbol en
cuestión. Un árbol recubridor mínimo o un árbol expandido mínimo es un árbol recubridor que pesa
menos o igual que otros árboles recubridores. Todo grafo tiene un bosque recubridor mínimo."

CONCLUSION
Grafo. Es el conjunto de vértices y aristas, los cuales, se representa gráficamente como un conjunto de
puntos llamados nodos y las aristas se representan por líneas o puentes que unen dichos nodos
La teoría de grafos sirve como un modelo matemático para estructuras en cualquier campo , pero una de
las mas importante en las aéreas de ciencias de la computación .
Árbol. Un árbol se define como un tipo de grafo que no contiene ciclos, es decir es un grafo acíclico y a su
vez es conexo. Quiere deciry que conecta a todos los puntos,. En un grafo con n vértices, los árboles
tienen exactamente n - 1 aristas, y hay nn-2 árboles posibles. Su importancia radica en que los árboles
son grafos que conectan todos los vértices utilizando el menor número posible de aristas.
CAPITULO II

ALGORITMO DE PRIM
ROSA GUEREQUETA GARCIA – ANTONIO VALLECILLO MORENO (2004)[7], En su libro Técnicas de
Desarrollos de Algoritmos nos dice:
"El algoritmo de Prim es tal vez el algoritmo de MST (Arboles Generadores Mínimos) más sencillo de
implementar y el mejor método para grafos densos. Este algoritmo puede encontrar el MST de cualquier
grafo conexo pesado.
Sea V el conjunto de nodos de un grafo pesado no dirigido. El algoritmo de Prim comienza cuando se
asigna a un conjunto U de nodos un nodo inicial Perteneciente a V, en el cual "crece" un árbol de
expansión, arista por arista. En cada paso se localiza la arista más corta (u, v) que conecta a U con V-U, y
después se agrega v, el vértice en V-U, a U. Este paso se repite hasta que V=U. El algoritmo de Prim es
de O(N2), donde | V | = N.
El siguiente ejemplo ilustra el funcionamiento del algoritmo.
La secuencia de ilustraciones va de izquierda a derecha y de arriba hacia abajo. La
primera imagen muestra el grafo pesado y las siguientes muestran el funcionamiento del algoritmo de
Prim y como va cambiando el conjunto U durante la ejecución.
Figura 1

Agregar un nodo al MST es un cambio incremental, para implementar el algoritmo de Prim debemos


enfocarnos en la naturaleza de ese cambio incremental. La clave está en notar que nuestro interés esta
en la distancia más corta de cada vértice de U a V-U.
Al U agregar un nodo v al árbol, el único cambio posible para cada vértice w fuera del árbol es que
agregar v coloca a w más cerca del árbol. Esto no es necesario verificar la distancia de w a todos los
demás nodos del árbol, solo se necesita verificar si la adición de v al árbol necesita actualizar dicho
mínimo. Esto se puede lograr agregando una estructura de datos simple para evitar repetir cálculos
excesivos, y hacer que el algoritmo sea más rápido y más simple.
El siguiente ejemplo ilustra la metodología anterior, utilizando una pila de aristas P, en donde las aristas
se van apilando en menor a mayor según el peso de la misma. La secuencia de ilustraciones va de
izquierda a derecha.
Figura 2
Se comienza en el nodo 0 y se apilan las aristas adyacentes a este nodo, en orden decreciente. La arista
mínima es la que está en el tope de la pila, así que se des apila y se agrega al MST.
Seguidamente se procede con el nodo 1 y se apilan sus aristas adyacentes, con la diferencia de que hay
que verificar si dichas aristas representan un nuevo camino mínimo con respecto a las aristas que ya
están introducidas en la pila. En este caso no se apila la arista 1-3 porque ya hay una arista que lleve a 3
con el mismo costo en la pila. Se toma 1-2 porque está en el tope y se procede con el nodo 2. Cuando se
va a apilar la arista 2-3, se encuentra que ya hay un camino que lleve a 3 pero de mayor costo, así que se
desopila 0-3 y luego se apila 2-3. Se agrega 2-3 al MST y termina el proceso, porque el conjunto de nodos
en el MST es igual al conjunto de vértices del grafo original."
ALFREDO CAICEDO BARRERO, GRACIELA WAGNER DE GARCÍA, ROSA MARÍA MÉNDEZ PARRA
(2010)[8], En su libro Introducción a la Teoría de Grafos dice:
"Supóngase N = {1, 2, 3,…,n}. El algoritmo de Prim comienza con un conjunto U inicializado con cualquier
nodo, por ejemplo {1}. Luego se hace crecer un árbol generador, arco por arco. En cada paso se
encuentra el arco más corto (u, v) que conecta a U y N – U y luego se adiciona v, el nodo en N – U, a U.
Se repite este paso hasta que U = N
El algoritmo es resumido en los siguientes pasos:
Algoritmo de PRIM.
Paso 0. Iniciar el grafo T con un solo nodo i escogido al azar: N = {i}, A = 0, T = ({i},0)
Paso 1. Seleccionar el arco (i, j) cuya longitud es la menor entre todos aquellos arcos adyacentes a T.
Adicionar este arco (i,j) a T y j al conjunto de nodos de T
Paso 2. Preguntar si T ya es un árbol que contiene todos los nodos de G y detenerse. En este caso
contrario repetir el paso 1"
CONCLUSION
El algoritmo de PRIM es un método para poder hallar un árbol recubridor mínimo en un grafo aciclico
conexo no dirigido que nos permita hallar en un grafo el coste mínimo para una serie de actividades.
CAPITULO III:

Aplicación del Algoritmo de Prim


Este algoritmo se usa normalmente para ahorrar recursos, su aplicación mas común es la implementación
de cables de redes, de servidores, de postes de luz entre otros.
Es decir el Algoritmo de Prim sirve para poder hallar el "árbol recubridor mínimo", en un grafo conexo no
dirigido.
Ejemplos
Aplicando el algoritmo de Prim en un problema de la vida real:
Situación: Implementación del cableado para el servicio de televisión por cable en ciertos puntos de un
sector de la ciudad de Puno.
Problema: Ahorrar la mayor cantidad de cable (recursos) en los puntos estratégicos (torres
de distribución) para llegar a todos los destinos deseados.
Datos: Distancia entre torres y casas es de 10 metros (cada casa)
Planteamiento: En el figura 3 se observa la ubicación de las torres de distribución y las viviendas
Figura 3
En la figura 4 transformamos el conjunto de torres y viviendas en un Grafo.
Figura 4

En la figura 5 Aplicamos el Algoritmo de Prim en el grafo para hallar el árbol recubrir mínimo o en otras
palabras la ruta optima para ahorra la distancia del cableado.
Figura 5
BIBLIOGRAFÍA
 Alfredo Caicedo Barrero, Graciela Wagner De García, Rosa María Méndez Parra (2010)
Introducción a la Teoría de Grafos (2da ED)
 Bernard Kolman – Robert c. Busby – Sharon Rross (1997) Estructura
Matematicas Discretas (2da ED). Francia.
 ELIAS MICHA (2003).Matematicas Discretas (2ta ED). Mexico.
 Jirí Matoušek,Jaroslav Nešetril(1998) Invitation to Discrete Mathematics (1ra ED) EE:UU.
 Rosa Guerequeta Garcia – Antonio Vallecillo Moreno (2004) Tecnicas de Desarrollos de
Algoritmos (1ra ED)
 Robert Sedgewick (1992) Algoritmos en C++ (1ra ED) EE.UU
 Seymour Lipschutz – Marc Lipson (2007). Matematicas Discretas (3ra Ed)
 
 
Autor:
Alexander Flores Mamani 
[1] ELIAS MICHA (2003).Matematicas Discretas (2ta ED). Mexico. PAG. 22, 19
[2] Seymour Lipschutz – Marc Lipson (2007). Matematicas Discretas (3ra Ed) PAG 158, 159
[3] Bernard Kolman – Robert c. Busby – Sharon Rross (1997) Estructura Matematicas Discretas (2da ED).
Francia. PAG. 198
[4] Jirí Matoušek,Jaroslav Nešetril(1998) Invitation to Discrete Mathematics (1ra ED) EE:UU. PAG. 124,
[5] Robert Sedgewick (1992) Algoritmos en C++ (1ra ED) EE.UU PAG 277
[6] Bernard Kolman – Robert C. Busby – Sharon Ross (1995) Estructuras de Matemáticas Discretas para
la Computación (3ra ED) Pag 321
[7] Rosa Guerequeta García – Antonio Vallecillo Moreno (2004) Técnicas de Desarrollos de Algoritmos
(1ra ED) Cap 4 Pag 10
[8] Alfredo Caicedo Barrero, Graciela Wagner De García, Rosa María Méndez Parra (2010) Introducción a
la Teoría de Grafos (2da ED) Pág. 109

Leer más: http://www.monografias.com/trabajos87/monografia-algoritmo-prim/monografia-algoritmo-
prim.shtml#ixzz4Z2ZppfNG

Algoritmo de Kruskal
El algoritmo de Kruskal es un algoritmo de la teoría de grafos para encontrar un árbol
recubridor mínimo en un grafo conexo y ponderado. Es decir, busca un subconjunto de
aristas que, formando un árbol, incluyen todos los vértices y donde el valor total de todas
las aristas del árbol es el mínimo. Si el grafo no es conexo, entonces busca un bosque
expandido mínimo (un árbol expandido mínimo para cada componente conexa). El
algoritmo de Kruskal es un ejemplo de algoritmo voraz.
Un ejemplo de árbol expandido mínimo. Cada punto representa un vértice, el cual puede ser un
árbol por sí mismo. Se usa el Algoritmo para buscar las distancias más cortas (árbol expandido) que
conectan todos los puntos o vértices.

Funciona de la siguiente manera:

 se crea un bosque B (un conjunto de árboles), donde cada vértice del grafo es


un árbol separado
 se crea un conjunto C que contenga a todas las aristas del grafo
 mientras C es no vacío
 eliminar una arista de peso mínimo de C
 si esa arista conecta dos árboles diferentes se añade al bosque,
combinando los dos árboles en un solo árbol
 en caso contrario, se desecha la arista
Al acabar el algoritmo, el bosque tiene un solo componente, el cual forma un árbol de
expansión mínimo del grafo.
Este algoritmo fue publicado por primera vez en Proceedings of the American
Mathematical Society, pp. 48–50 en 1956, y fue escrito por Joseph Kruskal.

Índice
  [ocultar] 

 1Pseudocódigo
 2Código en C++
 3Complejidad del algoritmo
 4Demostración de la correctitud
 5Ejemplo
 6Referencias
 7Enlaces externos

Pseudocódigo[editar]

función Kruskal(G)
Para cada v en V[G] hacer
Nuevo conjunto C(v) ← {v}.
Nuevo heap Q que contiene todas las aristas de G, ordenando por su
peso.
Defino un arbol T ← Ø
// n es el número total de vértices
Mientras T tenga menos de n-1 aristas y !Q.vacío() hacer
(u,v) ← Q.sacarMin()
// previene ciclos en T. agrega (u,v) si u y v están diferentes
componentes en el conjunto.
// Nótese que C(u) devuelve la componente a la que pertenece u.
Si C(v) ≠ C(u) hacer
Agregar arista (v,u) a T.
Merge C(v) y C(u) en el conjunto
Responder arbol T

Código en C++[editar]

// Declaraciones en el archivo .h
int cn; //cantidad de nodos
vector< vector<int> > ady; //matriz de adyacencia

// Devuelve la matriz de adyacencia del árbol mínimo.


vector< vector<int> > Grafo :: kruskal(){
vector< vector<int> > adyacencia = this->ady;
vector< vector<int> > arbol(cn);
vector<int> pertenece(cn); // indica a que árbol pertenece el nodo

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


arbol[i] = vector<int> (cn, 0);
pertenece[i] = i
}

int nodoA;
int nodoB;
int arcos = 1;
while(arcos < cn){
// Encontrar el arco mínimo que no forma ciclo y guardar los
nodos y la distancia.
int min = INF;
for(int i = 0; i < cn; i++)
for(int j = 0; j < cn; j++)
if(min > adyacencia[i][j] && adyacencia[i][j]!=0 &&
pertenece[i] != pertenece[j]){
min = adyacencia[i][j];
nodoA = i;
nodoB = j;
}
// Si los nodos no pertenecen al mismo árbol agrego el arco al
árbol mínimo.
if(pertenece[nodoA] != pertenece[nodoB]){
arbol[nodoA][nodoB] = min;
arbol[nodoB][nodoA] = min;

// Todos los nodos del árbol del nodoB ahora pertenecen al


árbol del nodoA.
int temp = pertenece[nodoB];
pertenece[nodoB] = pertenece[nodoA];
for(int k = 0; k < cn; k++)
if(pertenece[k] == temp)
pertenece[k] = pertenece[nodoA];

arcos++;
}
}
return arbol;
}

Complejidad del algoritmo[editar]


m el número de aristas del grafo y n el número de vértices, el algoritmo de Kruskal muestra
una complejidad O(m log m) o, equivalentemente, O(m log n), cuando se ejecuta sobre
estructuras de datos simples. Los tiempos de ejecución son equivalentes porque:

 m es a lo sumo n2 y log n2 = 2logn es O(log n).


 ignorando los vértices aislados, los cuales forman su propia componente del árbol
de expansión mínimo, n ≤ 2m, así que log n es O(log m).
Se puede conseguir esta complejidad de la siguiente manera: primero se ordenan las
aristas por su peso usando una ordenación por comparación (comparison sort) con una
complejidad del orden de O(m log m); esto permite que el paso "eliminar una arista de
peso mínimo de C" se ejecute en tiempo constante. Lo siguiente es usar una estructura de
datos sobre conjuntos disjuntos (disjoint-set data structure) para controlar qué vértices
están en qué componentes. Es necesario hacer orden de O(m) operaciones ya que por
cada arista hay dos operaciones de búsqueda y posiblemente una unión de conjuntos.
Incluso una estructura de datos sobre conjuntos disjuntos simple con uniones por rangos
puede ejecutar las operaciones mencionadas en O(m log n). Por tanto, la complejidad total
es del orden de O(m log m) = O(m log n).
Con la condición de que las aristas estén ordenadas o puedan ser ordenadas en un tiempo
lineal (por ejemplo, mediante el ordenamiento por cuentas o con el ordenamiento Radix), el
algoritmo puede usar estructuras de datos de conjuntos disjuntos más complejas para
ejecutarse en tiempos del orden de O(m α(n)), donde α es la inversa (tiene un crecimiento
extremadamente lento) de la función de Ackermann.

Demostración de la correctitud[editar]
Sea P un grafo conexo y valuado y sea Y el subgrafo de P producido por el algoritmo. Y no
puede tener ciclos porque cada vez que se añade una arista, ésta debe conectar vértices
de dos árboles diferentes y no vértices dentro de un subárbol. Y no puede ser disconexa
ya que la primera arista que une dos componentes de Y debería haber sido añadida por el
algoritmo. Por tanto, Y es un árbol expandido de P.
Sea Y1 el árbol expandido de peso mínimo de P, el cual tiene el mayor número de aristas
en común con Y. Si Y1=Y entonces Y es un árbol de expansión mínimo. Por otro lado,
sea e la primera arista considerada por el algoritmo que está en Y y que no está en Y1.
Sean C1 y C2 las componentes de P que conecta la arista e. Ya que Y1 es un
árbol, Y1+e tiene un ciclo y existe una arista diferente f en ese ciclo que también
conecta C1 y C2. Entonces Y2=Y1+e-f es también un árbol expandido. Ya que e fue
considerada por el algoritmo antes que f, el peso de e es al menos igual que el peso de f y
ya que Y1 es un árbol expandido mínimo, los pesos de esas dos aristas deben ser de
hecho iguales. Por tanto, Y2 es un árbol expandido mínimo con más aristas en común
con Y que las que tiene Y1, contradiciendo las hipótesis que se habían establecido antes
para Y1. Esto prueba que Y debe ser un árbol expandido de peso mínimo.
Otros algoritmos para este problema son el algoritmo de Prim y el algoritmo de Boruvka.

Ejemplo[editar]

Este es el grafo original. Los números de las aristas indican


su peso. Ninguna de las aristas está resaltada.

AD y CE son las aristas más cortas, con peso 5, y AD se ha


elegido arbitrariamente, por tanto se resalta.

Sin embargo, ahora es CE la arista más pequeña que no


forma ciclos, con peso 5, por lo que se resalta como segunda
arista.
La siguiente arista, DF con peso 6, ha sido resaltada
utilizando el mismo método.

Las siguientes aristas más pequeñas son AB y BE, ambas


con peso 7. AB se elige arbitrariamente, y se resalta. La
arista BD se resalta en rojo, porque formaría un ciclo ABD si
se hubiera elegido.

El proceso continúa marcando las aristas, BE con peso 7.


Muchas otras aristas se marcan en rojo en este
paso: BC (formaría el ciclo BCE), DE (formaría el
ciclo DEBA), y FE (formaría el ciclo FEBAD).

Finalmente, el proceso termina con la arista EG de peso 9, y


se ha encontrado el árbol expandido mínimo con peso total
de 39.

También podría gustarte