原题链接:数据结构-最小生成树
解题思路:这道题,我使用了Prime算法解决,以下是我的总结。
注意事项:二维数组不能开太大,1000足以,不然会爆掉
参考代码:
#include <bits/stdc++.h>
#define max 65535
#define size 1000
#define join 65534
#define ini 65532
using namespace std;
struct Edge
{
// 顶点表
int start;
// 邻接矩阵
int end;
// 顶点数,边数
int weight;
Edge()
{
weight = max - 1;
}
};
bool cmp(const Edge &a, const Edge b)
{
return a.weight < b.weight;
}
Edge e[size];
int s = 0;
typedef struct
{
// 顶点表
int vex[size];
// 邻接矩阵
int arc[size][size];
// 顶点数,边数
int numvex, numedge;
} MGroup;
void createGroup(MGroup *G)
{
int i, j, k, w;
// 创建图的过程就是将顶点表填入相应数值
//cout << "请输入顶点数和边数" << endl;
cin >> G->numvex;
//cout << "请输入顶点信息";
for (i = 0; i < G->numvex; i++)
{
G->vex[i] = i;
}
for (int i = 0; i < G->numvex; i++) // 再设计最小生成树时,一定要初始化,不然容易弄混淆,或者定义一个参数作为生成树的标志
fill(G->arc[i], G->arc[i] + (G->numvex), max);
//cout << "请输入边信息,依次是行,列,权值" << endl;
for (i = 0; i < G->numvex; i++)
{
for (int j = 0; j < G->numvex; j++)
{
int value;
cin >>value;
if (value)
{
G->numedge++;
G->arc[i][j] = value;
e[s].start = i;
e[s].end = j;
e[s].weight = value;
s++;
// 无向图是对称图
G->arc[j][i] = value; // 若是有向图,不加,因为有向图可能不是对称图,但是无向图一定是
}
}
}
}
int mintree_prime(MGroup *G)
{
int result = 0;
int min, i, j, k;
int adjvex[size];
int lowcost[size];
lowcost[0] = join;
adjvex[0] = 0;
for (i = 1; i < G->numvex; i++)
{
lowcost[i] = G->arc[0][i]; // 按照邻接表的值进行赋值,此时的lowcost只有第一行的数值
adjvex[i] = 0;
}
for (i = 1; i < G->numvex; i++)
{
min = max;
j = 1;
k = 0; // 存储最小顶点的下标
while (j < G->numvex) // 遍历所有顶点
{
if (lowcost[j] != join && lowcost[j] < min)
{
min = lowcost[j]; // 此时的最小值则记录下来提供给下一次操作
k = j;
}
j++;
} // 遍历完后,就会得到此时最短路径
//printf("(%d,%d)", adjvex[k], k); // 展示处此时连线,adjvex[K]表示当前最小顶点,表示所在图的行和列
result += G->arc[adjvex[k]][k];
lowcost[k] = join; // 已纳入了最小生成树
for (j = 1; j < G->numvex; j++) // 从0顶点开始了,所以不算0那个顶点,从1算起;
{
if (lowcost[j] != join && G->arc[k][j] < lowcost[j]) // 此时是第K行的值与65535比较
{
lowcost[j] = G->arc[k][j]; // 此时将lowcost数组刷新,然后多了一部分可遍历的点
adjvex[j] = k; // 刷新起点为当前最小值
}
}
}
return result;
}
int find(int *parents, int f) // 找没有环路的最优解,不从起点回来
{
while (parents[f]!=ini)//寻找是否有环,直到没有环为止,因为此时该点已经访问过,再用它必有一条回路
f = parents[f];
return f;//返回空闲位置
}
int Kruskal(MGroup *G)
{
int parents[size]; // 生成树数组c++默认为零
fill(parents, parents + G->numvex, ini);
int i, j, result = 0, n, m;
for (int i = 0; i < G->numedge; i++) // 遍历边集数组
{
n = find(parents, e[i].start);
m = find(parents, e[i].end);
if (n != m)
{
parents[n] = m;//表示将他们连在一起,标志访问
//printf("(%d->%d)", e[i].start, e[i].end);
result += e[i].weight;
}
}
return result;
}
int main()
{
MGroup *p = new MGroup();
createGroup(p);
sort(e, e + size - 100, cmp);
cout << mintree_prime(p) << endl;
cout << Kruskal(p);
return 0;
}0.0分
1 人评分
C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:
一点编程也不会写的:零基础C语言学练课程
解决困扰你多年的C语言疑难杂症特性的C语言进阶课程
从零到写出一个爬虫的Python编程课程
只会语法写不出代码?手把手带你写100个编程真题的编程百练课程
信息学奥赛或C++选手的 必学C++课程
蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程
发表评论 取消回复