【问题描述】
已知含有n个顶点的带权连通无向图,采用邻接矩阵存储,邻接矩阵以三元组的形式给出,只给出不包括主对角线元素在内的下三角形部分的元素,且不包括不相邻的顶点对。分别采用prim算法和kruskal算法,求该连通图的最小生成树的权值之和。
【输入形式】
第一行给出结点个数n和三元组的个数count,以下每行给出一个三元组,数之间用空格隔开。(注意这里顶点的序号是从1到n,而不是0到n-1,程序里要小心!)
【输出形式】
两种算法求解的最小生成树的权值之和
【样例输入】
5 8
2 1 7
3 1 6
3 2 8
4 1 9
4 2 4
4 3 6
5 2 4
5 4 2
【样例输出】
18
18
//Kruskal 算法
typedef struct
{
int begin;
int end; //储存边的头尾和权值
int weight;
}Edge;
Edge edge[MAX_VERTEX_NUM];
void Sort(Graph &G) //找出最小权值
{
int i,j;
Edge temp;
for(i=0;i<=G.arcnum-2;i++)
for(j=0;j<=G.arcnum-i-2;j++)
if(edge[j].weight>edge[j+1].weight)
{
temp=edge[j];
edge[j]=edge[j+1];
edge[j+1]=temp;
}
}
int p[MAX_VERTEX_NUM];//定义点的集合
int rank[MAX_VERTEX_NUM];
int Find(int x)//查找集合i(一个元素是一个集合)的源头(递归实现)
{
int y=x;
while(p[y]!=y)
{
y=p[y];
}
int root=y;
y=x;
while(p[y]!=y)
{
int w=p[y];
p[y]=root;
y=w;
}
return root;
}
void Union(int x,int y)//加入团体
{
int u=Find(x);
int v=Find(y);
if(rank[u]<=rank[v])
{
p[u]=v;
if(rank[u]==rank[v])
rank[v]++;
}
}
int MiniSpanTree_Kruskal(Graph &G)
{
int i,j,k=0,sum=0;
for(i=0;i<G.vexnum;i++)//初始化点的集合.刚开始每个点互相独立,自己是自己的上级
{
p[i]=i;
rank[i]=0;
}
for(i=0;i<G.vexnum;i++)//把边储存
{
for(j=0;j<G.vexnum;j++)
{
if(G.arcs[i][j].adj!=INFINITY&&i<j)
{
edge[k].begin=i;
edge[k].end=j;
edge[k].weight=G.arcs[i][j].adj;
k++;
}
}
}
Sort(G);//边的权值排序
k=0;
for(i=0;i<G.arcnum,k<G.vexnum-1;i++)//n个点加入n-1条边
{
if(Find(edge[i].begin)!=Find(edge[i].end))//假如begin和end上级不一样也就是不在一个团体
{
Union(edge[i].begin,edge[i].end);//加入
sum+=edge[i].weight;
k++;//已连接边数+1
}
}
return sum;
}
int main()
{
Graph G;
CreateMatrix(&G);
cout<<MiniSpanTree_Prim(G,1)<<endl;
cout<<MiniSpanTree_Kruskal(G);
}