先讲思路,答案第一段代码,题目在最后;
思路:这里的图时矩阵实现,所以要把矩阵遍历一遍并且把边提取出来初始化为Edge边集;并且为了判断是否成环,要设立一个集合S(并查集),初始化后的边集还要根据lowcost排升序,这样在接下来选取边的时候可以直接顺序取并判断; 完成以上后,进入循环for(i=0;i<ie;i++)来遍历边集Edge的每条边(v,w);找下标调用了裁判程序给定的LocateVex函数(根据值确定其在G中下标的函数),if(Find(S,v)!=Find(S,w))说明(v,w)不在同一棵树上,不会成环,就把v和w连接(连接即让它们祖先一样,S[w]=S[v]),并且给代表最小生成树边数的MstS加一,如果满足MstS==G.vexnum-1,则说明边已经收集满了,跳出循环;
和书上有点差别。先排序再生成;书上是一边生成一边堆排序找最小;
答案代码如下:
int Find(int S[],int a){
int i;
for(i=a;S[i]!=i;i=S[i]);
S[a]=i;//顺便路径压缩以下
return i;
}
void Kruskal(AMGraph G){
static int S[9999],i,j,ie,v,w,MstS=0;
for(i=0;i<G.vexnum;i++){//初始化集合
S[i]=i;
}
for(i=0;i<G.vexnum;i++){//初始化边结构体
for(j=0;j<G.vexnum;j++){
if(G.arcs[i][j]<MaxInt&&j>i){//根据输出要求,每条边先输出下标大的
Edge[ie].Head=G.vexs[i];
Edge[ie].Tail=G.vexs[j];
Edge[ie++].lowcost=G.arcs[i][j];//记录边长,同时ie++
}
}
}
//对边结构体排升序 冒泡
for(i=0;i<ie;i++){
for(j=0;j<ie-i-1;j++){
if(Edge[j+1].lowcost<Edge[j].lowcost){
struct Evode t=Edge[j];
Edge[j]=Edge[j+1];
Edge[j+1]=t;
}
}
}
for(i=0;i<ie;i++){//走完原图的边集 i就是每次的最小边在Edge里的下标
v=LocateVex(G,Edge[i].Head);//找到这条边的起点
w=LocateVex(G,Edge[i].Tail);
// printf("%d %d %d %d\n",v,w,Find(S,v),Find(S,w));
if(Find(S,v)!=Find(S,w)){//说明不会成换环
S[w]=S[v];//S[v]=S[w]
MstS++;//收集的边数加一
printf("%c->%c\n",Edge[i].Head,Edge[i].Tail);//输出已经确定的边
if(MstS==G.vexnum-1) break;//已经收集够边数了 结束
}
//else 丢弃这条边,就什么也不做
}
}
题目如下:
试实现克鲁斯卡尔最小生成树算法。
函数接口定义:
void Kruskal(AMGraph G);
其中 G
是基于邻接矩阵存储表示的无向图。
裁判测试程序样例:
#include <stdio.h>
#define MVNum 10
#define MaxInt 32767
typedef struct{
char vexs[MVNum];
int arcs[MVNum][MVNum];
int vexnum,arcnum;
}AMGraph;
struct Evode{
char Head;
char Tail;
int lowcost;
}Edge[(MVNum * (MVNum - 1)) / 2];
int Vexset[MVNum];
void CreateUDN(AMGraph &G);//实现细节隐藏
void Kruskal(AMGraph G);
int main(){
AMGraph G;
CreateUDN(G);
Kruskal(G);
return 0;
}
/* 请在这里填写答案 */
输入样例:
第1行输入结点数vexnum和边数arcnum。第2行输入vexnum个字符表示结点的值,接下来依次输入arcnum行,每行输入3个值,前两个字符表示结点,后一个数表示两个结点之间边的权值。
7 9
0123456
0 1 28
0 5 10
1 2 16
1 6 14
2 3 12
3 6 18
3 4 22
4 5 25
4 6 24
输出样例:
按最小生成树的生成顺序输出每条边。
0->5
2->3
1->6
1->2
3->4
4->5