任务描述
相关知识
带权图的邻接矩阵
边表
树的表示
最小生成树
最小生成树的prim算法
编程要求
测试说明
任务描述
本关任务:使用prim算法构造最小生成树。
相关知识
带权图的邻接矩阵
本实验针对无向图。邻接矩阵Adj是图的常用存储结构,如果每条边(u,v)定义了权值w(u,v), 则可以用Adj[u][v]=w(u,v)来表示。
在带权图中,没有边的Adj[u][v]=?. 这需要根据具体应用来设置。 比如求顶点之间的最长简单路径,则没有边处可设Adj[u][v]=负无穷大, 如果求顶点之间的最短路径,则没有边处Adj[u][v]=无穷大。
一般认为一个结点不存在到自身的边,因此对角线Adj[u][u]的设置可参照没有边的设置方法。
因此把所有边的信息(端点1,端点2,权值)输入,就可以得到一个带权图。
边表
如果图有n个顶点e条边,则邻接矩阵的存储空间是n
2
. 对于顶点很多的图占用内存比较大。如果e并不大,可以用邻接矩阵的稀疏表示方法,只表示有边的信息,其实也就是前面学过“三元组”法:(端点1,端点2,权值), 上图可以用一个边表表示-(0,1,6),(0,2,2),(1,2,3),....一共7个边。
可见边表表示是邻接矩阵的稀疏表示法。但是边表有个缺点就是很难查询,比如想知道边(1,2)的权值,只能在边表中穷举访问,时间是O(e), 但邻接矩阵是Adj[1][2]直接得到,时间是O(1)
树的表示
很多应用中,并不关心树根,把树作为一个特殊的图。此时当然也可以采用邻接矩阵来表示,而且树的边数e=n-1, 离n
2
差很远,因此用稀疏表示边表更合理。
本实验中因为要经常查询图的边的信息,所以图用邻接矩阵来表示,但对树并没有做访问,所以树用边表表示就行。
最小生成树
最小生成树针对连通图。 对于一个具有n个顶点的连通图G,它的边的数目e>=n-1. 如果从中选出n-1条边,还是能连接n个顶点构成子连通图,称为生成树。 一般情况下,图G的生成树并不唯一。
如果G是带权图,则在众多的生成树中,可以选择边的权和最小的生成树,是为最小生成树。最小生成树也常常不唯一。
最小生成树的prim算法
图G=(V,E)的最小生成树可以逐个顶点逐条边的选择加入:
第一步:任意选取一个顶点,不妨选顶点0。初始化顶点集合A={0},顶点集合B=V-{0},减号是集合中去掉的意思。初始化最小生成树Tree=空集。算法后续步骤是逐个将B中的点移到A中。
第二步:用一个数组dis记录B中每个点i到集合A的最短边信息, dis[i]=二元组(R,v), v是最短边(i,v)在A中的顶点,R是(i,v)的长度。初始时A={0},故对B中所有的i, dis[i]=(Adj[i][0], 0)
第三步:在B中选择一个u, 满足距离A最短,即dis[u].R是所有dis[i].R中最小。 将u从B中移到A中,即A=A+{u}, B=B-{u},并得到最小生成树的一条边(u,dis[u].v), Tree=Tree+{(u,dis[u].v)}
第四步:由于A中新增加u点, 故B中每个点i到A的最短边可能会是(i,u),需要检查更新, if (dis[i].R< Adj[i][u]) {dis[i].R=Adj[i][u]; dis[i].v=u}
第五步:如果Tree中的边数已经到达n-1,输出tree,停止计算。否则回到第三步。
如果你看上面的有困难,那请配合阅读网文。
编程要求
根据提示,在右侧编辑器补充代码,计算并输出最小生成树。输入包括图的邻接矩阵,输出生成树的边表。
测试说明
平台会对你编写的代码进行测试:
开始你的任务吧,祝你成功!
#include <stdio.h>
#define INF 99999999
#define MAX 100
struct edge {
int u;
int v;
}; //记录边的两个端点
double Adj[MAX][MAX];
edge Tree[MAX];
double Prim(int n, double Adj[][MAX], edge Tree[])
// n是顶点个数,Adj[0:n][0:n]存放了邻接矩阵
// 最小生成树的边填写到Tree中
// 返回值是Tree中边的权和
{
int i,j,k,p,q,wm,count=0;
double sum=0;
q=p=n-1;
Adj[q][q]=1;
for(k=0;k<n-1;k++)
{
wm=INF+1;
for(i=0;i<n;i++)
{
if(Adj[i][i]==1)
{
for(j=0;j<n;j++)
{
if((Adj[j][j]==INF)&&Adj[i][j]<wm)
{
wm=Adj[i][j];
p=i;
q=j;
}
}
}
}
Adj[q][q]=1;
Tree[count].u=p;
Tree[count].v=q;
count++;
sum+=Adj[p][q];
}
return sum;
}