Algoritmo ganancioso para construir árvore geradora mínima: algoritmo kruskal, algoritmo prim

1. Definição:
emGráfico não direcionado conectadoG(V,E)Encontre um Esubconjunto acíclico de arestas em T, de modo que possa conectar todos os nós e ter o menor peso.
a)Como T é acíclico, pode ser considerado uma árvore
B)Uma vez que é gerado pelo grafo G, é chamado de (grafo G) árvore geradora
C)Uma vez que T tem o menor peso, é chamada de árvore geradora mínima.
Como T é acíclico, os vértices V devem ter arestas V-1.

2. Estratégia gananciosa:
cada vez que uma aresta da árvore de abrangência mínima cresce, os ciclos V-1 são executados para completar a construção da árvore. As bordas de crescimento devem ser bordas leves (peso mínimo) e não formar um anel.
Método: algoritmo kruskal (Kruskal) ou algoritmo prim (primo)

3. Algoritmo Prim (primo):
Este algoritmo pode ser chamado de método de adição de pontos.Cada iteração seleciona o ponto correspondente à aresta de menor custo e adiciona-o à árvore geradora mínima. O algoritmo começa a partir de qualquer vértice se cresce gradualmente para cobrir todos os vértices de todo o gráfico conectado.

3.1. Fluxo e gráfico do algoritmo:
Entrada: gráfico G(V,E)e qualquer nó ucomo ponto de partida; saída: conjunto de arestas P

  1. O nó use junta à coleção de nós U;
  2. Selecione a Uaresta de menor custo conectada aos nós do conjunto para unir o conjunto P(como arestas <u,v>) e vunir os nós conectados (como ) ao conjunto U;
    (se houver várias arestas com o mesmo peso, você pode escolher um deles à vontade);
  3. Repita a etapa 2 até que todos os nós se juntem ao conjunto U.

Insira a descrição da imagem aqui
3.2. Código C ++:

#include <queue>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
struct edge {
    
     // 边的定义
	int start;
	int end;
	int weight;
	edge(int x, int y, int z) :start(x), end(y), weight(z) {
    
    }
	bool operator< (const edge& tmp) const {
    
     //用于优先队列的比较函数
		return weight > tmp.weight;
	}
};

const int NUM = 6;
int G[NUM][NUM]; //假设图已经定义好了,如G[0][2] = 5; 5为权重
void MiniSpanTree_prim(int(*G)[NUM], int root)
{
    
    
	vector<int> V; //记录MST已经包含的点;
	V.push_back(root);
	priority_queue<edge> edge_all; // 放入权重边,自动排序
	for (int i = 0; i < NUM; i++) {
    
     // 放入与起点连接的边
		if (G[root][i] != 0) {
    
     // 0 代表没有路
			edge tmp(root, i, G[root][i]);
			edge_all.push(tmp);
		}
	}
	cout << "Prim :" << endl;
	for (int i = 0; i < NUM - 1; i++) {
    
     //共N-1条边
		edge curr = edge_all.top(); //取得代价最小边
		edge_all.pop();
		while (find(V.begin(), V.end(), curr.end) != V.end()) {
    
     //边终点若已包含,则丢弃后换一条边
			curr = edge_all.top();
			edge_all.pop();
		}
		V.push_back(curr.end); //放入这条边的终点v
		cout << curr.start << " --> " << curr.end << " " << curr.weight << endl; // 输出MST的边
		for (int j = 0; j < NUM; j++) {
    
     // 加入终点v连接的边
			if (G[curr.end][j] != 0 && find(V.begin(), V.end(), j) == V.end()) {
    
    
				edge tmp(curr.end, j, G[curr.end][j]);
				edge_all.push(tmp);
			}
		}
	}
}

4. Algoritmo de Kruskal (Kruskal):
Este algoritmo pode ser chamado de método de borda aditiva . O número mínimo inicial da borda da árvore geradora é 0. Cada iteração seleciona uma borda de custo mínimo que satisfaz a condição e a adiciona ao conjunto de arestas da árvore geradora mínima no.

4.1. Fluxo e diagrama do algoritmo:
entrada: gráfico G(V,E); saída: conjunto de arestas P.

  1. Classifique todas as arestas no gráfico do menor ao maior custo;
  2. Considere os n vértices no gráfico como uma floresta de n árvores independentes;
  3. Selecione as arestas do menor ao maior peso, u,vSe os dois vértices da aresta selecionada pertencem a duas árvores diferentes, eles se tornam uma aresta da árvore de abrangência mínima e as duas árvores são fundidas em uma árvore. Caso contrário, pegue a borda com o menor peso e tente novamente.
  4. Repita (3) até que todos os vértices estejam em uma árvore ou haja n-1 arestas.

Insira a descrição da imagem aqui

4.2. Código C ++:

#include <queue>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
struct edge {
    
     // 边的定义
	int start;
	int end;
	int weight;
	edge(int x, int y, int z) :start(x), end(y), weight(z) {
    
    }
	bool operator< (const edge& tmp) const {
    
     //用于优先队列的比较函数
		return weight > tmp.weight;
	}
};

const int NUM = 6;
int G[NUM][NUM]; //假设图已经定义好了,如G[0][2] = 5; 5为权重
void MiniSpanTree_kruskal(int(*G)[NUM])
{
    
    
	int node_coll[NUM] = {
    
     0 }; //判断节点是否属于一棵树
	int count = 1; // 用于不同树的标记
	priority_queue<edge> edge_all; // 放入权重边,自动排序
	for (int i = 0; i<NUM; i++) {
    
     //放入所有边,并自动排序
		for (int j = 0; j<NUM; j++) {
    
    
			if (G[i][j] != 0) {
    
    
				edge tmp(i, j, G[i][j]);
				edge_all.push(tmp);
			}
		}
	}
	for (int i = 0; i<NUM - 1; i++) {
    
     //共N-1条边
		edge tmp = edge_all.top(); // 取代价最小边
		edge_all.pop();
		while (node_coll[tmp.start] == node_coll[tmp.end] && node_coll[tmp.start] != 0 && node_coll[tmp.end] != 0) {
    
     // 找到属于不同树的边
			tmp = edge_all.top();
			edge_all.pop();
		}
		cout << tmp.start << " --> " << tmp.end << " " << tmp.weight << endl; // 输出MST的边
		if (node_coll[tmp.start] == 0 && node_coll[tmp.end] == 0) {
    
     //不同树的边的情况1
			node_coll[tmp.start] = count;
			node_coll[tmp.end] = count;
			count++;
		}
		else if (node_coll[tmp.start] == 0 && node_coll[tmp.end] != 0) {
    
     //不同树的边的情况2
			node_coll[tmp.start] = count;
			node_coll[tmp.start] = node_coll[tmp.end];
		}
		else if (node_coll[tmp.start] != 0 && node_coll[tmp.end] == 0) {
    
     //不同树的边的情况3
			node_coll[tmp.start] = count;
			node_coll[tmp.end] = node_coll[tmp.start];
		}
		else if (node_coll[tmp.start] != 0 && node_coll[tmp.end] != 0) {
    
     //不同树的边的情况4
			node_coll[tmp.start] = count;
			for (int i = 0; i<NUM; i++) {
    
    
				if (node_coll[i] = node_coll[tmp.end]) {
    
    
					node_coll[i] = node_coll[tmp.start];
				}
			}
		}
	}
}

Material de referência: Dois métodos de spanning tree mínimo (algoritmo de Kruskal e algoritmo de Prim)
Introdução ao algoritmo 23.2 Algoritmo de Kruskal e algoritmo de Prim

Resumindo:

1. O algoritmo kruskal é o método de adição, o algoritmo prim é o método de adição e a ideia do algoritmo de memória é boa.

Acho que você gosta

Origin blog.csdn.net/qq_33726635/article/details/106024969
Recomendado
Clasificación