图(2)

最小代价生成树定义

在含n个顶点的无向连通图G中,若存在由n-1条边连通n个顶点的子图G',
称G'为G的一棵生成树(spanning tree).
若果无向连通图的每一条边都赋了一个权值,则称此图为网络(network).
对于网络,如何寻找一棵生成树使得各条边的权值之和最小,是一个问题.
在一个网络的各种生成树中,具有最小代价的生成树称为最小代价生成树(minimum cost spanning tree)
简称最小生成树(minimum spanning tree 即MST)

Prim算法

设网络G={V,E},V={0,1,2,,,n-1}.
设U为V的子集,然后从V-U的集合中找出一顶点x,
该顶点x与U集合中的某点之间的边是最小权值边且不会造成回路.
然后将顶点x加入U集合中,反复执行同样的步骤,直到U=V为止.
#include<iostream>
using namespace std;
#define MaxSize 20
#define inf  2147483647
//图定义 
struct Graph{
	int V[MaxSize];          //存储顶点的数组 
	int M[MaxSize][MaxSize]; //存储边的数组 
	int n;					 //图所含顶点个数 
}; 
//根据顶点集V 边集合E 创建图的领接矩阵 
void Create(Graph &G,int *V,int vn,int *E,int en,int action){
	int i,j,k,w;
	G.n=vn;
	for(i=0;i<G.n;i++)
		G.V[i]=V[i];		
	for(i=0;i<G.n;i++){
		for(j=0;j<G.n;j++)
			if(i==j)
				G.M[i][j]=0;
			else
				G.M[i][j]=inf;	
	}	
	for(k=0;k<en;k++){
		i=E[3*k+0];
		j=E[3*k+1];
		w=E[3*k+2];
		G.M[i][j]=w;
		if(action==0) //如果是无向图 
			G.M[j][i]=w;
	}	
}
//Prim算法 图的最小生成树
void Prim(Graph G,int sv){
	int UC[2][MaxSize];
	int newUC[2][MaxSize];
	int i,j,k,n,min,col,choice;
	n=G.n;                //图所含顶点个数
	for(j=0;j<n;j++){
		UC[0][j]=inf;		//置U到V-U的初始代价为inf
		UC[1][j]=-1;		//置U为空集
	}
	k=sv;			//取起始顶点sv进入U集
	choice=1;		//挑选边数
	while(choice<n){
		for(i=0;i<2;i++)
			for(j=0;j<n;j++)
				if(i==0)
					newUC[i][j]=G.M[k][j];//据带权邻接矩阵给出顶点k到j的代价
				else
					newUC[i][j]=k;	//顶点k进入U集
		//比较newUC与UC对应列的代价,如果newUC中代价小于等于UC中代价
		//则用newUC中的列置换UC中的对应列			
		for(j=0;j<n;j++)
			if(newUC[0][j]<=UC[0][j]){
				UC[0][j]=newUC[0][j];   //newUC的第j列置换UC的第j列
				UC[1][j]=newUC[1][j];
			}
		//寻找UC中除了0之外的最小代价所在列	
		min=inf;col=0;
		for(j=0;j<n;j++)
			if(UC[0][j]<min&&UC[0][j]!=0){
				min=UC[0][j];	//顺序搜索最小代价所在列
				col=j;
			}
		//输出挑选的最小生成树的边与权值	
		cout<<"边("<<UC[1][col]<<","<<col<<"),权值"<<min<<endl;
		//再取进入U集顶点,进入下一轮挑选
		k=col;
		choice++;	
	}
} 
//输出邻接矩阵
void Display(Graph G){
	int i,j;
	cout<<"顶点"<<"\t";
	for(i=0;i<G.n;i++)
		cout<<"V"<<G.V[i]<<"\t";
	cout<<endl;
	for(i=0;i<G.n;i++){
		cout<<"V"<<G.V[i]<<"\t";
		for(j=0;j<G.n;j++)
			if(G.M[i][j]==inf)
				cout<<"inf"<<"\t";
			else
				cout<<G.M[i][j]<<"\t";	
		cout<<endl;	
	}
} 
int main(){
	int V[6]={0,1,2,3,4,5};
	int E[10][3]={{0,1,6},{0,5,10},{0,4,12},{1,2,3},{1,3,5},{1,4,8},{2,3,7},{3,4,11},{3,5,9},{4,5,16}};
	Graph G;
	Create(G,&V[0],6,&E[0][0],10,0);
	cout<<"图的领接矩阵"<<endl;
	Display(G); 	
	cout<<"最小代价生成树"<<endl;
	Prim(G,0); 

Kruskal算法

kruskal算法是将所有边按权值由小到大排序,
然后从权值最小的边开始挑选起,构架最小生成树,
若加入的边会造成回路则舍弃不用,直到所有边被挑选完为止.
#include<iostream>
using namespace std;
#define MaxSize 20
#define inf  2147483647
//带权边的定义
struct Edge{
	int x,y,w;  //边的起点,终点,权值 
}; 
//图定义 
struct Graph{
	int V[MaxSize];          //顶点 
	Edge E[MaxSize];         //带权边 
	int n;					 //顶点个数
	int e;                   //边数 
}; 
//根据顶点集V 边集合E 创建图的领接矩阵 
void Create(Graph &G,int *V,int vn,int *E,int en){
	G.n=vn;
	G.e=en; 
	for(int i=0;i<G.n;i++)
		G.V[i]=V[i];			
	for(int k=0;k<en;k++){
		G.E[k].x=E[3*k+0];
		G.E[k].y=E[3*k+1];
		G.E[k].w=E[3*k+2];
	}
}
//输出邻接矩阵
void Display(Graph G){
	cout<<"起点"<<"\t"<<"终点"<<"\t"<<"权值"<<endl;
	for(int i=0;i<G.e;i++)
		cout<<G.E[i].x<<"\t"<<G.E[i].y<<"\t"<<G.E[i].w<<endl;
}
//选择排序
void Sort(Graph &G){
	int i,j,min,pos,flag;
	Edge temp;
	for(i=0;i<G.e-1;i++){
		min=G.E[i].w;
		pos=i;
		flag=1;
		for(j=i+1;j<G.e;j++){
			if(min>G.E[j].w){
				min=G.E[j].w,pos=j;flag=0;
			}
		}
		if(flag==0){
			temp=G.E[i];
			G.E[i]=G.E[pos];
			G.E[pos]=temp;	
		}
	} 
} 
//Kruskal算法
void MST(Graph G){
	int i,j,m1,m2,n1,n2;
	for(i=0;i<G.e;i++){
		m1=G.E[i].x;
		m2=G.E[i].y;
		n1=G.V[m1];
		n2=G.V[m2];
		if(n1!=n2){
			cout<<"边("<<m1<<","<<m2<<"),代价:"<<G.E[i].w<<endl;
			for(j=0;j<G.e;j++)
				if(G.V[j]==n2)
					G.V[j]=n1; 
		}
	}
} 
int main(){
	int V[6]={0,1,2,3,4,5};
	int E[10][3]={{0,1,6},{0,5,10},{0,4,12},{1,2,3},{1,3,5},{1,4,8},{2,3,7},{3,4,11},{3,5,9},{4,5,16}};
	Graph G;
	Create(G,&V[0],6,&E[0][0],10);
	Sort(G);
	cout<<"带权图的边排序"<<endl;
	Display(G); 	
	cout<<"最小代价生成树"<<endl;
	MST(G); 
} 

写于2020-10-26

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值