Buscar

Algoritmo de Prim

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 9 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 9 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 9 páginas

Continue navegando


Prévia do material em texto

Algoritmo de Prim
Na ciência da computação o algoritmo de Prim é um algoritmo guloso empregado para encontrar uma árvore geradora mínima (MST), num grafo conectado, valorado e não direcionado. Isso significa que o algoritmo encontra um subgrafo do grafo original no qual a soma total das arestas é minimizada e todos os vértices estão interligados. O algoritmo foi desenvolvido em 1930 pelo matemático Vojtěch Jarník e depois pelo cientista da computação Robert Clay Prim em 1957 e redescoberto por Edsger Dijkstra em 1959 (O algoritmo foi publicado por Prim em 1961 e por Dijkstra pouco depois.).
Outros algoritmos conhecidos para encontrar árvores geradoras mínimas são os algoritmo de Kruskal e o de Boruvka. No entanto estes algoritmos podem ser empregados em grafos desconexos, enquanto o algoritmo de Prim precisa de um grafo conexo.
Algoritmo
Para descrever a aplicação do algoritmo de Prim a um grafo conexo G com custos nas arestas, convém recorrer ao conceito de franja.  A  franja de uma subárvore T de G é o conjunto de todas as arestas de G que têm uma ponta em T e outra ponta fora.   A franja de T nada mais é que o leque do conjunto de vértices de T. 
Cada iteração do algoritmo de Prim começa com uma subárvore T.  No início da primeira iteração, T consiste em um único vértice.  O processo iterativo consiste no seguinte: 
enquanto  a franja de T não é vazia  faça 
seja e uma aresta da franja que tem custo mínimo 
acrescente  e  a  T 
devolva  T 
Como se vê, o algoritmo de Prim tem caráter guloso: em cada iteração, abocanha a aresta que parece mais promissora localmente sem se preocupar com o efeito global dessa escolha.
Grafo Usado: Vamos aplicar o algoritmo de Prim nesse grafo, ele é conexo e valorado.
Passo 1: Iniciaremos a partir do Vértice “0”.
Vértices selecionados: “0”.
Franja: “2, 3”.
Possíveis caminhos: “0-2, 0-3”.
Menor custo: “0-2”
Passo 2:
Vértices selecionados: “0, 2”.
Franja: “1, 3, 4”.
Possíveis caminhos: “0-3, 2-1, 2-3, 2-4”.
Menor custo: “2-4”
Passo 3:
Vértices selecionados: “0, 2, 4”.
Franja: “1, 3, 5, 6”.
Possíveis caminhos: “0-3, 2-1, 2-3, 4-1, 4-3, 4-5, 4-6”.
Menor custo: “4-3”
Passo final:
Implementação com Matriz
Biblioteca
As funções “DIGRAPHinsertA e GRAPHinsertE”, agora recebem um 4º parâmetro que se refere ao valor do caminho (custo).
#include "stdio.h"
#include "stdlib.h"
#define Vertex int
#define Edge Arc
#define EDGE ARC
#define graph digraph
#define Graph Digraph
#define GRAPHinit DIGRAPHinit
#define GRAPHshow DIGRAPHshow
#define maxV 100
typedef struct digraph *Digraph; // Objeto do tipo Digraph contém o endereço de um digraph
typedef struct { // Arco
 Vertex v; // Vértice inicial v
 Vertex w; // Vértice final w
 } Arc;
struct digraph { // Digrafo
 int V; // Número de vértices
 int A; // Número de arestas
 int **adj; // Ponteiro para a matriz de adjacência (são ou não vizinhos)
 };
Arc ARC (Vertex v, Vertex w); // Recebe dois vértices e devolve um arco, com ponto inicial v e final w;
int **MATRIXint (int r, int c, int val); // Aloca uma matriz com linhas r - 1 e colunas c - 1, recebendo um valor val;
Digraph DIGRAPHinit (int v); // Devolve o endereço de um novo digrafo. Inicialização;
void DIGRAPHinsertA (Digraph G, Vertex v, Vertex w, int valor); // Insere arco v-w no digrafo G. Se v == w ou o digrafo já tem arco v-w, não faz nada;
void DIGRAPHshow (Digraph G); // Para cada vértice v de G, imprime em uma linha, os vértices adjacentes a v;
void GRAPHinsertE (Graph G, Vertex v, Vertex w, int valor); // Insere uma aresta v-w no grafo G;
Arc ARC (Vertex v, Vertex w) {
 Arc e;
 e.v = v;
 e.w = w;
 return e;
}
int **MATRIXint (int r, int c, int val) {
 Vertex i, j;
 int **m = malloc(r * sizeof(int *));
 for (i = 0; i < r; i++)
 m[i] = malloc(c * sizeof(int));
 for (i = 0; i < r; i++) {
 for (j = 0; j < c; j++)
 m[i][j] = val;
 }
 return m;
}
Digraph DIGRAPHinit (int v) {
 Digraph G = malloc(sizeof *G);
 G -> V = v;
 G -> A = 0;
 G -> adj = MATRIXint(v, v, 0);
 return G;
}
void DIGRAPHinsertA (Digraph G, Vertex v, Vertex w, int valor) {
 if (v != w && G -> adj[v][w] == 0) {
 G -> adj[v][w] = valor;
 G -> A++;
 }
}
void DIGRAPHshow (Digraph G) {
 Vertex v, w;
 for (v = 0; v < G -> V; v++) {
 printf("%2d: ", v);
 for (w = 0; w < G -> V; w++) {
 if (G -> adj[v][w] != 0)
 printf("%2d ", w);
 }
 printf("\n");
 }
}
void GRAPHinsertE (Graph G, Vertex v, Vertex w, int valor) {
 DIGRAPHinsertA(G, v, w, valor);
 DIGRAPHinsertA(G, w, v, valor);
}
A função Prim
void prim(Graph G, Vertex V) {
 int selecionados[G->V], franja[G->V];
 int i, j, menor_custo = 98;
 Arc arco;
 Graph MST;
 //inicializa os vetores
 MST = DIGRAPHinit(G->V);
 for (i = 0; i < G->V; i++) {
 selecionados[i] = 0;
 franja[i] = 0;
 }
 selecionados[V] = 1;
 while (menor_custo != 99) { // Quando o menor custo for o custo máximo, significará que não tem franja.
 //zera franja
 for (i = 0; i < G->V; i++)
 franja[i] = 0;
 //define franja
 for (i = 0; i < G->V; i++)
 if (selecionados[i] == 1)
 for (j = 0; j < G->V; j++)
 if (G->adj[i][j] != 0 && selecionados[j] == 0)
 franja[j] = 1;
//Escolhe menor custo
 menor_custo = 99; //Inicializa o menor custo com o custo maximo
 for (i = 0; i < G->V; i++)
 if (selecionados[i] == 1)
 for (j = 0; j < G->V; j++)
 if (i != j && franja[j] == 1 && G->adj[i][j] != 0)
 if (G->adj[i][j] < menor_custo && G->adj[i][j] != 0) {
 menor_custo = G->adj[i][j];
 arco.v = i;
 arco.w = j;
 }
 GRAPHinsertE(MST, arco.v, arco.w, 1);
 selecionados[arco.w] = 1;
 selecionados[arco.v] = 1;
 }
 printf("\n\nArvore MST: \n");
 DIGRAPHshow(MST);
}
Implementação com Listas de adjacência
Biblioteca
As funções “DIGRAPHinsertA, GRAPHinsertE e link NEW”, agora recebem um parâmetro adicional que se refere ao valor do caminho (custo). A “struct node” recebe uma nova variável chamada “valor”, que receberá o valor(custo) do arco.
#include "stdio.h"
#include "stdlib.h"
#define Vertex int
#define graph digraph
#define Graph Digraph
#define GRAPHinit DIGRAPHinit
#define GRAPHshow DIGRAPHshow
typedef struct digraph *Digraph; // Objeto do tipo Digraph contém endereço de um digraph
typedef struct node *link; // link é um ponteiro para um node
struct digraph { // Estrutura Digraph
 int V; // Número de vértices
 int A; // Número de arcos
 link *adj; // Ponteiro para um vetor de listas de adjacência
 };
/* A lista de adjacência de um vértice v é composta por nós do tipo node
 Um link é um ponteiro para um node
 Cada nó da lista contém um vizinho w de v e o endereço do nó seguinte da lista */
struct node {
 Vertex w;
 int valor;
 link next;
 };
link NEW (Vertex w, link next, int valor); // Devolve um novo nó x, com x.w = w e x.next = next;
Digraph DIGRAPHinit (int V); // Devolve um novo digrafo com vértices de 0 a V - 1;
void DIGRAPHinsertA (Digraph G, Vertex v, Vertex w, int valor); // Insere um arco v-w, caso v==w ou o arco já exista, não faz nada;
void DIGRAPHshow (Digraph G); // Para cada vértice v de G, imprime em uma linha, os vérticesadjacentes a v;
void GRAPHinsertE (Graph G, Vertex v, Vertex w, int valor); // Insere uma aresta v-w no grafo G;
link NEW (Vertex w, link next, int valor) {
 link x = malloc(sizeof *x);
 x -> w = w;
 x -> valor = valor;
 x -> next = next;
 return x;
}
Digraph DIGRAPHinit (int V) {
 Vertex v;
 Digraph G = malloc(sizeof *G);
 G -> V = V;
 G -> A = 0;
 G -> adj = malloc(V * sizeof(link));
 for (v = 0; v < V; v++)
 G -> adj[v] = NULL;
 return G;
}
void DIGRAPHinsertA (Digraph G, Vertex v, Vertex w, int valor) {
 link p;
 if (v == w)
 return;
 for (p = G -> adj[v]; p != NULL; p = p -> next)
 if (p -> w == w)
 return;
 G -> adj[v] = NEW(w, G -> adj[v], valor);
 G -> A++;
}
void DIGRAPHshow (Digraph G) {
 Vertex v;
 link p;
 for (v = 0; v < G -> V; v++) {
 printf("%2d: ", v);
 for (p = G -> adj[v]; p != NULL; p = p -> next) {
 printf("%2d[%2d] ", p -> w, p->valor);
 }
 printf("\n");
 }
}
void GRAPHinsertE (Graph G, Vertex v, Vertex w, int valor) {
 DIGRAPHinsertA(G, v, w, valor);
 DIGRAPHinsertA(G, w, v, valor);
}
A função Prim
void prim_listas(Graph G, Vertex V) {
 int w, v, valor, i_s, i_f, nodup, menor_custo;
 link p;
 Vertex i, j;
 Vertex selecionados[G->V], franja[G->V], franja_valor[G->V];
 Graph MST;
 //inicializa os vetores
 MST = DIGRAPHinit(G->V);
 for (i = 0; i < G->V; i++) {
 selecionados[i] = 0;
 franja[i] = 0;
 }
 selecionados[V] = 1;
 //loop principal
 while (menor_custo != 99) {// Quando o menor custo for o custo máximo, significará que não tem franja.
 //zera a franja
 for (i = 0; i < G->V; i++)
 franja[i] = 0;
 //define a franja
 for (i = 0, j = 0; i < G->V; i++)
 if (selecionados[i] != 0)
 for (p = G->adj[i]; p != NULL; p = p->next)
 if (p != NULL && selecionados[p->w] == 0){
 //Para não duplicar valores na franja
 nodup = 1;
 for (i_f = 0; franja[i_f] != 0; i_f++)
 if (franja[i_f] == p->w)
 nodup = 0;
 if (nodup == 1) {
 franja[j] = p->w;
 j++;
 }
 }
 //Escolhe menor custo
 menor_custo = 99; //Inicializa o menor custo com o custo maximo
 for (i = 0, j = 0; i < G->V; i++)
 if (selecionados[i] != 0)
 for (p = G->adj[i]; p != NULL; p = p->next)
 if (p != NULL && p->valor < menor_custo ) {
 //evita escolher um uma aresta contendo 2 selecionados
 nodup = 1;
 for (i_s = 0; i_s < G->V; i_s++)
 if (selecionados[i_s] == 1 && i_s == p->w)
 nodup = 0;
 if (nodup == 1) {
 menor_custo = p->valor;
 v = i;
 w = p->w;
 valor = p-> valor;
 }
 }
 GRAPHinsertE(MST, v, w, valor);
 selecionados[w] = 1;
 selecionados[v] = 1;
 }
 printf("\n\nArvore MST: \n");
 DIGRAPHshow(MST);
}
Fontes:
www.ime.usp.br/~pf/algoritmos_para_grafos/aulas/prim.html
http://pt.wikipedia.org/wiki/Algoritmo_de_Prim