图论Graph Theory(4):最小生成树

一、最小生成树概念

最小生成树是一副连通加权无向图中一棵权值最小的生成树。

二、Prim’s算法

#include <iostream>
#include <cstdlib>
#include <cstdio>
using namespace std;

const int V = 5;
const int MAXX = 1314520;

void printMST(int parent[],int graph[V][V]) 
{
	for(int i = 1;i<V;i++) {
		cout<<parent[i]<<"--"<<i<<" == "<<graph[i][parent[i]]<<endl;
	}
}
void primMST(int graph[V][V])
{
	// 存储最小生成树
	int parent[V];

	// 用来寻找最小边,初始化为INT_MAX
	int num[V];

	// 判断节点是否已经在最小生成树中
	bool MSTset[V];

	for(int i=0;i<V;i++) {
		num[i] = MAXX;
		MSTset[i] = false;
	}

	// 设置0为起点
	num[0] = 0;
	// 设为根节点 ,第一个节点是根节点
	parent[0] = -1;

	for(int count = 0;count < V-1;count++) {

		// 找到num最小且不在MSTset中的节点
		int minn = MAXX;
		int min_index = 0;
		for(int i=0;i<V;i++) {
			if((MSTset[i]==false)&&(num[i]<minn)) {
				minn = num[i];
				min_index = i;
			}
		}

		// 将其加入MSTset
		MSTset[min_index] = true;
		int u = min_index;

		// 更新那些未加入MSTset节点的num的值和parent的地址,
		for(int v=0;v<V;v++) {
			// u和v是连接的
			if(graph[u][v] && MSTset[v]==false && graph[u][v] < num[v]) {
				num[v] = graph[u][v];
				parent[v] = u;
			}
		}
	}

	//输出MST
	printMST(parent,graph);
}
int main()
{
	int graph[V][V] = { { 0, 1, 0, 3, 0 }, 
						{ 2, 0, 3, 9, 4 }, 
						{ 0, 2, 0, 0, 9 }, 
						{ 5, 7, 0, 0, 8 }, 
						{ 0, 4, 6, 9, 0 } }; 
	primMST(graph);
	return 0;
}

三、Kruskal算法

//freopen("hao.txt","r",stdin);
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
using namespace std;

class Edge
{
	public:
		int src;
		int dest;
		int weight;
};

class Graph
{
	public:
		int V;			//节点数
		int E;			//边数
		Edge* edge;
};

Graph* createGraph(int V,int E)
{
	Graph* graph = new Graph;
	graph->V = V;
	graph->E = E;
	graph->edge = new Edge[E];
	return graph;
}

class subset
{
	public:
		int rank;
		int parent;
};

int find(subset subsets[],int i){
	if(subsets[i].parent != i)
		subsets[i].parent = find(subsets,subsets[i].parent);

	return subsets[i].parent;
}

void Union(subset subsets[],int x,int y)
{
	int x_root = find(subsets,x);
	int y_root = find(subsets,y);

	if(subsets[x_root].rank < subsets[y_root].rank)
		subsets[x_root].parent = y_root;
	else if(subsets[x_root].rank > subsets[y_root].rank)
		subsets[y_root].parent = x_root;
	else{
		subsets[y_root].parent = x_root;
		subsets[x_root].rank++;
	}
}
int cmp(const void* a,const void* b)
{
	Edge* a1 = (Edge*)a;
	Edge* b1 = (Edge*)b;
	return a1->weight > b1->weight;
}
void Kruskal(Graph* graph)
{
	int V = graph->V;
	int E = graph->E;

	Edge result[V];
	int v = 0;
	int e = 0;

	qsort(graph->edge,graph->E,sizeof(graph->edge[0]),cmp);		//排序每一条边从小到大

	subset* subsets = new subset[V * sizeof(subset)];			//开辟空间

	for(int i=0;i<V;i++) {										//初始化subsets
		subsets[i].parent = i;
		subsets[i].rank = 0;
	}

	while((v < V-1)&&(e < graph->E)) {
		Edge next_edge = graph->edge[e++];		//取出每一条边

		int x = find(subsets,next_edge.src);
		int y = find(subsets,next_edge.dest);

		if(x!=y){								//不在一个集合才能合并,不然成环
			result[v++] = next_edge;
			Union(subsets,x,y);
		}
	}
	printf("This is result of Kruskal MST:\n");
	for(int i=0;i<v;i++)
		cout<<result[i].src<<" -- "<<result[i].dest<<" = "<<result[i].weight<<endl;
}
int main()
{

	int V = 4;
	int E = 5;
	Graph* graph = createGraph(V,E);

	// add edge 0-1  
    graph->edge[0].src = 0;  
    graph->edge[0].dest = 1;  
    graph->edge[0].weight = 10;  
  
    // add edge 0-2  
    graph->edge[1].src = 0;  
    graph->edge[1].dest = 2;  
    graph->edge[1].weight = 6;  
  
    // add edge 0-3  
    graph->edge[2].src = 0;  
    graph->edge[2].dest = 3;  
    graph->edge[2].weight = 5;  
  
    // add edge 1-3  
    graph->edge[3].src = 1;  
    graph->edge[3].dest = 3;  
    graph->edge[3].weight = 15;  
  
    // add edge 2-3  
    graph->edge[4].src = 2;  
    graph->edge[4].dest = 3;  
    graph->edge[4].weight = 4;  

    Kruskal(graph);

	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值