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
输出结果:
时间复杂度