图论——最小生成树

本文详细介绍了图论中的最小生成树概念,并重点讲解了Kruskal算法和Prim算法的实现原理。Kruskal算法通过并查集避免环路,Prim算法则从一个顶点出发逐步构建。代码示例展示了两种算法的具体步骤,帮助读者理解这两种贪心算法在解决最小生成树问题时的应用。
摘要由CSDN通过智能技术生成

我们先来了解一下什么是生成树?

1.生成树:在图G中,包含G中所有顶点且不构成回路的极小连通图

那么最小生成树(MST)便是一个代价最小的生成树

我们如何构建最小生成树呢?正常思维便是一步一步找到代价最小的一部分最后达到全局的最小【有贪心算法的思想】

接下来,我们介绍两种算法,kruscal算法和prim算法。

kruskal算法

思想:一开始每个顶点分属不同集合【先这么理解】,每次摘选权值最小的边及其两端顶点,将此两顶点归为同一集合,重复操作,过程中避免形成环路,直至所有顶点都在同一个集合中。

难点:避免形成环路

我们先来思考什么样的存储结构适合kruskal,每次都要选取两顶点一边,不论是邻接矩阵还是邻接表都有点麻烦,因此我们采用一种新的结构

typedef struct EdgeType{
	int v1,v2,w;//点v1,点v2,及权值 
}EdgeType; 

typedef struct Graph{
	EdgeType edge[100];
	int vexnum,edgenum;
}Graph;

而针对避免环路,我们设定一个parent数组,用于记录每个顶点的根节点,根节点起初都是-1,根节点不一样或-1才进行合并

代码实现:

#include<iostream>
#include<stdlib.h>
using namespace std;
typedef struct EdgeType{
	int v1,v2,w;//点v1,点v2,及权值 
}EdgeType; 

typedef struct Graph{
	EdgeType edge[100];
	int vexnum,edgenum;
}Graph;

int parent[100]; 
void kruskal(Graph &G);//图G 
int findRoot(int parent[],int v);//求根节点 
void outputMST(EdgeType edge);//输出 

void kruskal(Graph &G){
	for(int i=0;i<G.edgenum;++i){
		parent[i]=-1;
	}
	for(int num=0,i=0;i<G.edgenum;++i){
		int vex1=findRoot(parent,G.edge[i].v1);
		int vex2=findRoot(parent,G.edge[i].v2);
		if(vex1!=vex2){
			outputMST(G.edge[i]);
			parent[vex2]=vex1;
			num++;
			if(num==G.edgenum)	return;
		} 
	}
}
//parent值为-1时,t自身就是根节点;非-1时,parent值为根节点 
int findRoot(int parent[],int v){
	while(parent[v]>-1){
		v=parent[v];
	}
	return v;
}

void outputMST(EdgeType edge){
	cout<<"("<<edge.v1<<" "<<edge.v2<<") 权值:"<<edge.w<<endl;	 
}

int cmp(const void *v1,const void *v2){
	EdgeType *x=(EdgeType*) v1;
	EdgeType *y=(EdgeType*) v2;
	return x->w-y->w;
}

int main(){
	Graph G;
	cin>>G.vexnum>>G.edgenum;
	for(int i=0;i<G.edgenum;++i){
		cin>>G.edge[i].v1>>G.edge[i].v2>>G.edge[i].w;
	}
	qsort(G.edge,G.edgenum,sizeof(EdgeType),cmp);
	kruskal(G);
	return 0;
} 

prim算法:

思想:与kruskal不同的是,prim算法是从某一个顶点处罚,根据边来摘选最小,直到构成生成树

代码实现:

#include <iostream>
using namespace std;

#define maxint 32767
#define max 100
typedef int vextype;
typedef int edgetype;
//邻接矩阵
typedef struct graph{
	vextype vexs[max];
	edgetype edge[max][max];
	int vexnum,edgenum;
}graph; 

typedef struct shortedge{
	vextype adjvex;
	edgetype lowcost;
}shortedge;
shortedge s[100];

void creategraph(graph &g);
void prim(graph &g,int start);
int minedge(shortedge s[],int vexnum);
void outputMST(int a,shortedge b);
int locate(graph &g,vextype v);

void creategraph(graph &g){
	cin>>g.vexnum>>g.edgenum;
	for(int i=0;i<g.vexnum;++i){
		cin>>g.vexs[i];
	}
	for(int i=0;i<g.edgenum;++i){
		for(int j=0;j<g.edgenum;++j){
			g.edge[i][j]=maxint;
		}
	}
	for(int i=0;i<g.edgenum;++i){
		vextype v1,v2;
		edgetype w;
		cin>>v1>>v2>>w;
		int x=locate(g,v1);
		int y=locate(g,v2);
		g.edge[x][y]=w;
		g.edge[y][x]=g.edge[x][y];
	}
}

int locate(graph &g,vextype v){
	for(int i=0;i<g.vexnum;++i){
		if(v==g.vexs[i])	return i;
	}
	return -1;
}

void prim(graph &g,int start){
	for(int i=0;i<g.vexnum;++i){
		s[i].lowcost=g.edge[start][i];//把初始权值付给shortage数组 
		s[i].adjvex=start;//把初始顶点赋给shortage数组,代表是当前点到各边 
	}
	s[start].lowcost=0;//进行同化,把起点start放入集合U 
	for(int i=0;i<g.vexnum-1;++i){
		int k = minedge(s,g.vexnum);//寻找最短边的邻接点k返回其下标 
		outputMST(k,s[k]);//输出当前最短路径 【k--相当于邻接点位置;s[k]--相当于包含了vex即要到k的点和cost即他俩之间的权值】
		s[k].lowcost=0;//将k也进行同化 
		for(int j=0;j<g.vexnum;++j){
			if(g.edge[k][j]<s[j].lowcost){
				s[j].lowcost=g.edge[k][j];
				s[j].adjvex=k;
			}
		} 
	}
}

int minedge(shortedge *s,int vexnum){
	shortedge min_s;
	min_s.lowcost=32767,min_s.adjvex=0;
	for(int i=0;i<vexnum;++i){
		if(s[i].lowcost!=0)//等于0代表已被同化 
			if(min_s.lowcost>s[i].lowcost){
				min_s.lowcost=s[i].lowcost;
				min_s.adjvex=i;
			}
	}
	return min_s.adjvex;
}

void outputMST(int a,shortedge b){
	cout<<b.adjvex+1<<" "<<a+1<<" 权值:"<<b.lowcost<<endl;
}

int main(){
	graph g;
	creategraph(g);
	prim(g,0);
	return 0 ;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值