最小生成树(prim算法)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_26760433/article/details/84784767

1.最小生成树

图G的生成树是一颗包含G的所有顶点的树,树上所有有权值总和表示代价,那么在G的所有的生成树中代价最小的生成树称为图G的最小生成树,简称(MST).

在这里插入图片描述

图二就是图一的最小生成树。

2.普里姆算法(prim)

prim算法和Dijkstra算法类似,也是贪心法。
1).输入:一个加权连通图,其中顶点集合为V,边集合为E;
2).初始化:Vnew = {x},其中x为集合V中的任一节点(起始点),Enew = {},为空;
3).重复下列操作,直到Vnew = V:
a.在集合E中选取权值最小的边<u, v>,其中u为集合Vnew中的元素,而v不在Vnew集合当中,并且v∈V(如果存在有多条满足前述条件即具有相同权值的边,则可任意选取其中之一);
b.将v加入集合Vnew中,将<u, v>边加入集合Enew中;
4).输出:使用集合Vnew和Enew来描述所得到的最小生成树。

代码实现上图一的最小生成树

#include<iostream>
#include<vector>
#include<queue>
using namespace std;
class road
{
public:
	int end;    //边的终点
	int weight;  //边的长度
};
class Graph
{
public:
	int v;             //顶点个数
	int *mark;          //标记是否访问过,访问过为1,否则为0
	vector<road> *adj;  //邻接表

	Graph(int n);          //构造函数
	~Graph();                           //析构函数
	void addEdge(int b,int e,int w);    //添加边
};
Graph::Graph(int n)
{
	v=n; 
	mark=new int[n];
	adj=new vector<road>[n];
	for(int i=0;i<n;i++)              //初始化标记为0
		mark[i]=0;
}
Graph::~Graph()
{
	delete []mark;
	delete []adj;
}
void Graph::addEdge(int b,int e,int w)    //因为是无向图,添加双向边
{
	road r1;
	r1.end = e;
	r1.weight = w;
	adj[b].push_back(r1);

	road r2;
	r2.end = b;
	r2.weight = w;
	adj[e].push_back(r2);
}
class Dist
{
public:
	int pre;
	int length;
	int index;
	friend bool operator<(const Dist &a,const Dist &b)
	{
		return a.length>b.length;
	}
};

void prim(Graph &g,int s)    //s是起始点
{
	Dist * D = new Dist[g.v];   //申请空间
	for(int i=0;i<g.v;i++)        //初始化
	{
		D[i].index  = i;
		D[i].length = 1<<30;
		D[i].pre = s;
	}

	priority_queue<Dist> aqueue;
	int now_node = s;
	for(int i=0;i<g.v-1;i++)
	{
		vector<road>::iterator ii = g.adj[now_node].begin();
		for(;ii!=g.adj[now_node].end();ii++)    //刷新与now_node相邻的顶点的值
		{
			if( g.mark[ii->end] ==0 && D[ii->end].length > ii->weight )
			{
				D[ii->end].length = ii->weight;
				D[ii->end].pre = now_node;
				aqueue.push(D[ii->end]);
			}
		}
		Dist d;
		bool FOUND=false;
		while(!aqueue.empty())
		{
			d = aqueue.top();
			aqueue.pop();
			if( g.mark[d.index]== 0)
			{
				FOUND=true;
				break;
			}
		}
		if(!FOUND)    //有不可到达的顶点
			break;
		
		g.mark[now_node]=1;
		now_node=d.index;
		cout<<D[now_node].pre<<"->"<<D[now_node].index<<" length: "<<D[now_node].length<<endl;
	}

}
int main()
{
	Graph g(7);
	g.addEdge(0,1,20);
	g.addEdge(0,4,1);
	g.addEdge(1,3,4);
	g.addEdge(1,2,6);
	g.addEdge(3,5,12);
	g.addEdge(3,6,8);
	g.addEdge(2,6,2);
	g.addEdge(4,5,15);
	g.addEdge(5,6,10);
	prim(g,0);
	return 0;
}

运行结果

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_26760433/article/details/84784767