最小生成树之Prim,Kruskal

1.如果无向图中,边上有权值,则称该无向图为无向网

2.如果无向网中的每个顶点都相通,称为连通网

3.最小生成树(Minimum Cost Spanning Tree)是代价最小的连通网的生成树,即该生成树上的边的权值和最小

最小生成树的准则

1.必须使用且仅使用连通网中的n-1条边来联结网络中的n个顶点;

2.不能使用产生回路的边;

3.各边上的权值的总和达到最小。

4.常用于道路建设、线路铺设等应用中计算成本 

 

普里姆(Prim)算法生成最小生成树

#include<bits/stdc++.h>
using namespace std;
#define MAX 65535
#define N 50
struct MGraph
{
	string name[N];
	int flag[N];
	int arc[N][N];
	int Vexnum;
	MGraph(){
	}
	MGraph(int n,string x[])
	{
		Vexnum=n;
		for(int i=0;i<n;i++)
			name[i]=x[i];
		memset(flag,0,sizeof(int)*n);
		for(int i=0;i<n;i++)
			for(int j=0;j<n;j++)
			{
				arc[i][j]=MAX;
			}
	}
	int find(string x)
	{
		for(int i=0;i<Vexnum;i++)
			if(x==name[i])
				return i;
	}
	void SetArc(int m)
	{
		string a,b;
		int i,j,k;
		while(m--)
		{
			cin>>a>>b>>k;
			i=find(a);
			j=find(b);
			arc[i][j]=k;
			arc[j][i]=k;
		}	
	}
};
void MiniSpanTree_Prim(MGraph G)
{
	int min,i,j,k;
	int adjvex[G.Vexnum];//保存相关顶点的下标
	int lowcost[G.Vexnum]  ;//保存相关顶点间边的权值
	lowcost[0]=0;//初始化第一个权值为0.即Vo加入生成树
//lowcost的值为0,在这里就是此下标的顶点已经加入生成树 
	adjvex[0]=0;//初始化第一个顶点下标为0
	for(i=1;i<G.Vexnum;i++)//循环除下标为0外的全部项 
	{
		lowcost[i]=G.arc[0][i];//将Vo顶点与之有边的权值存入数组中
		adjvex[i]=0;//初始化都为Vo的下标
	}
	for(i=1;i<G.Vexnum;i++)
	{
		min=MAX;
		j=1;
		k=0;
		while(j<G.Vexnum)  //循环全部顶点 
		{
			if(lowcost[j]!=0&&lowcost[j]<min)
			{
				//如果权值不为0,且权值小于min
				min=lowcost[j];
				k=j;//把当前最小值的下标存入K
				 
			}
			j++;
		}
		cout<<adjvex[k]<<" -> "<<k<<" :min= "<<min<<endl;
		//打印当前顶点边中权值最小的边的下标和权值 
		lowcost[k]=0; 
		//将当前顶点的权值设置为0,表示此顶点已经完成任务
		for(j=1;j<G.Vexnum;j++)
		{
			if(lowcost[j]!=0&&G.arc[k][j]<lowcost[j])
			{
				//若下标为K顶点个边权值小于此前这些顶点为被加入生成树的权值
				lowcost[j]=G.arc[k][j];
				//将较小的权值存入lowcost
				
				adjvex[j]=k;
				//将下标为K的顶点存入adjvex 
			}
		} 
	}
			
} 
int main()
{
	int t,n,m,i;
	string x[N];
	cin>>t;
	while(t--)
	{
		cin>>n;
		for(i=0;i<n;i++)
			cin>>x[i];
		MGraph p(n,x);
		cin>>m;
		p.SetArc(m);
		MiniSpanTree_Prim(p);
	}
	return 0;
}

 

 

克鲁斯卡尔(Kruskal)算法生成最小生成树

 把邻接矩阵转化成边集数组,并且对他们从小到大排序

 

#include<bits/stdc++.h>
using namespace std;
#define N 50
//对边集数组Edge结构的定义 
struct Edge
{
	int begin;
	int end;
	int weight;	
	void set(int b,int e,int w)
	{
		begin=b;
		end=e;
		weight=w;
	}
};
struct MGraph
{
	string name[N];
	int flag[N];
	int Vexnum; //顶点个数
	int num;//边的个数 
	Edge edge[N];
	MGraph(){
	}
	MGraph(int n,string x[])
	{
		Vexnum=n;
		for(int i=0;i<n;i++)
			name[i]=x[i],flag[i]=0;
	}
	int findIndex(string x)
	{
		for(int i=0;i<Vexnum;i++)
			if(x==name[i])
				return i;
		return -1;
	}
	void setEdge(int m)
	{
		string a,b;
		int i;
		num=m;
		int x,k,j;
		for(i=0;i<num;i++)
		{
			cin>>a>>b>>x;
			k=findIndex(a);
			j=findIndex(b);
			edge[i].set(k,j,x);
		} 
		Sort();
	}
	void Sort()
	{
		for(int i=1;i<num;i++)
		{
			for(int j=0;j<num-i;j++)
			{
				if(edge[j].weight>edge[j+1].weight)
				{
					Edge temp;
					temp=edge[j];
					edge[j]=edge[j+1];
					edge[j+1]=temp;
				}
			}
		}
	}
};
int Find(int *parent ,int f)//查找连线顶点尾部的下标 
{
	while(parent[f]>0)
		f=parent[f];
	return f;
}
void MinSpanTree_Kruskal(MGraph G)
{
	int i,n,m;
	int parent[G.Vexnum]; 
	memset(parent,0,sizeof(int)*G.Vexnum);
	for(i=0;i<G.num;i++) //循环每一条边 
	{
		n=Find(parent,G.edge[i].begin)  ;
		m=Find(parent,G.edge[i].end)  ;
		if(n!=m)
		{
			parent[n]=m;
			//将此边的结尾顶点放入下标为起点的parent中
			//表示此顶点已经在生成树集合中 
			
			cout<<G.edge[i].begin<<"->"<<G.edge[i].end;
			cout<<" "<<G.edge[i].weight<<endl;
		}
	}
}
int main()
{
	int t,i,j,n,m;
	string x[N] ;
	cin>>t;
	while(t--)
	{
		cin>>n;
		for(i=0;i<n;i++)
			cin>>x[i];
		MGraph p(n,x);
		cin>>m;
		p.setEdge(m);
		MinSpanTree_Kruskal(p);
	 } 
	return 0;
}

样例输入:

5

9

V0 V1 V2 V3 V4 V5 V6 V7 V8

15

V0 V1 10

V0 V5 11

V1 V2 18

V1 V6 16

V1 V8 12

V2 V8 8

V2 V3 22

V3 V8 21

V3 V6 24

V3 V7 16

V3 V4 20

V4 V5 26

V4 V7 7

V5 V6 17

V6 V7 19

 

输出结果:

 

 

时间复杂度

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值