7-1 实验7-1(最小生成树-Prim算法)
利用Prim算法计算最小生成树。
输入格式:
输入第一行是两个整数n1 n2,其中n1表示顶点数(则顶点编号为0至n1-1),n2表示图中的边数。
之后有n2行输入,每行输入表示一条边,格式是“顶点1 顶点2 权重”。其中,权重是整数类型。
例如:
4 6
0 1 4
0 2 5
0 3 6
1 2 2
1 3 1
2 3 4
输出格式:
以0号顶点为初始顶点,依次输出每轮选择的边,每条边占一行,格式为“顶点1 顶点2”。其中顶点1与0号顶点在同一个集合中。
全部边输出后再输出最小生成树的权重,之后输出一个换行符。
例如,对于上面的示例输入,输出为:
0 1
1 3
1 2
7
输入样例:
在这里给出一组输入。例如:
3 3
0 1 10
0 2 30
1 2 25
输出样例:
在这里给出相应的输出。例如:
0 1
1 2
35
代码长度限制 16 KB 时间限制 400 ms 内存限制 64 MB 栈限制 8192 KB
C++代码
#include <iostream>
using namespace std;
#define MaxVertexNum 100 // 设置最大顶点数
#define INFINITY 65535 // 表示无穷大(无边)♾️设置为双字节无符号整型最大值65535
#define ERROR -1 // 表示无父节点
typedef int DataType; // 顶点存储的数据设为整型
typedef int WeightType; // 边的权重设置为整型
typedef int Vertex; // 用定点下标设置为顶点,为整型
// 边的定义
typedef struct ENode* PtrToENode;
struct ENode {
Vertex V1, V2; // 有向边<V1, V2>
WeightType Weight; // 权重
};
typedef PtrToENode Edge;
// --------------------------组成图--------------------------
// 邻接点定义
typedef struct AdjVNode* PtrToAdjVNode;
struct AdjVNode {
Vertex AdjV; // 邻接点下标
WeightType Weight; // 边权重
PtrToAdjVNode Next; // 指向下一个邻接点的指针w
};
// 顶点表头结点的定义
typedef struct VNode {
PtrToAdjVNode FirstEdge; // 边表头指针
DataType Data; // 存顶点的数据
} AdjList[MaxVertexNum]; // AdjList是邻接表类型,AdjList是结构体数组,长度为MaxVertexNum,元素为VNode
// 图结点的定义
typedef struct GNode* PtrToGNode;
struct GNode {
int Nv; // 顶点数
int Ne; // 边数
AdjList G; // 邻接表
};
typedef PtrToGNode LGraph; // 以邻接表方式存储的图类型
// ----------------------------------------------------------
// 初始化一个有VerTexNum个顶点但没有边的图
LGraph CreatGraph(int VertexNum) {
LGraph Graph = (LGraph)malloc(sizeof(struct GNode));
Graph->Nv = VertexNum;
Graph->Ne = 0;
// 初始化邻接表头指针
for (Vertex V = 0; V < Graph->Nv; V++) {
Graph->G[V].FirstEdge = NULL;
}
return Graph;
}
void InsertEdge(LGraph Graph, Edge E) {
// 插入边 E(<V1, V2>, W)
// 为V1建立邻接点V2
PtrToAdjVNode NewNode = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode));
NewNode->AdjV = E->V2;
NewNode->Weight = E->Weight;
// 将V2插入图Graph
NewNode->Next = Graph->G[E->V1].FirstEdge; // 邻接点V2尾部指向顶点域V1所指的邻接点
Graph->G[E->V1].FirstEdge = NewNode; // 顶点域V1指向邻接点V2
// 对于无向图,
// 还要插入边 E(<V2, V1>, W)
NewNode = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode));
NewNode->AdjV = E->V1;
NewNode->Weight = E->Weight;
// 将V1插入图Graph
NewNode->Next = Graph->G[E->V2].FirstEdge; // 邻接点V1尾部指向顶点域V2所指的邻接点
Graph->G[E->V2].FirstEdge = NewNode; // 顶点域V2指向邻接点V1
}
// 建立以邻接表方式存储的图
LGraph BuildGraph() {
int Nv;
Edge E;
LGraph Graph;
cin >> Nv; // 读入顶点个数
Graph = CreatGraph(Nv); // 初始化只有Nv个顶点的图
if (Nv == 0) {
Graph->Ne = 0;
return Graph;
}
cin >> Graph->Ne; // 读入边数
if (Graph->Ne != 0) { // 如果有边
E = (Edge)malloc(sizeof(ENode)); // 建立边结点
//读入边,输入格式为:起点 终点 权重
for (int i = 0; i < Graph->Ne; i++) {
cin >> E->V1 >> E->V2 >> E->Weight;
InsertEdge(Graph, E); // 插入边
}
// 若需要输入顶点数据,写在这
}
return Graph;
}
/*
* 返回未收录顶点中Dist最小的顶点
* @param Graph 邻接表图
* @param Dist 距离数组(Dist[V]表示V到生成树的最小权值)
* @return 最小距离的顶点下标,无则返回ERROR
*/
Vertex FindMinDist(LGraph Graph, WeightType Dist[]) {
WeightType MinDist = INFINITY; // 初始化最短距离
Vertex MinV = ERROR; // 返回未收录顶点中Dist最小的顶点
for (Vertex V = 0; V < Graph->Nv; V++) {
// 未收录的(Dist[V]!=0)且距离更小
if (Dist[V] != 0 && Dist[V] < MinDist) {
MinDist = Dist[V];
MinV = V;
}
}
return MinV;
}
// prim算法
WeightType Prim(LGraph Graph, LGraph *MST) {
WeightType Dist[Graph->Nv]; // 距离数组
Vertex Parent[Graph->Nv]; // 父节点数组
WeightType totalWeight = 0; // 最小生成树总权值
int VCount = 0; // 已收录的顶点数
Vertex Start = 0; // 起始顶点,默认选0
// 初始化Dist和Parent数组
for (Vertex V = 0; V < Graph->Nv; V++) {
Dist[V] = INFINITY;
Parent[V] = ERROR; // ERROR表示无父结点
}
// 收录起始顶点Start
Dist[Start] = 0; // 标记起始结点Start已收录
VCount++; // 更新已收录顶点数
// 初始化起始顶点的邻接边距离
PtrToAdjVNode W = Graph->G[Start].FirstEdge; // W为Strat的邻接点
while (W != NULL) { // 遍历Start的邻接点
if (W->Weight < Dist[W->AdjV]) {
Dist[W->AdjV] = W->Weight; // 以Start为中心,更新Dist
Parent[W->AdjV] = Start; // 更新父节点
}
W = W->Next; // 下一个邻接点
}
// 创建空的最小生成树(邻接表法)
*MST = CreatGraph(Graph->Nv);
// 迭代选择最小权值边,构建生成树
for (int i = 1; i < Graph->Nv; i++) { // 迭代选择最小权值边,构建生成树
Vertex V = FindMinDist(Graph, Dist); // 返回未收录顶点中Dist最小的顶点
if (V == ERROR) break; // 无收录顶点,退出(FindMinDist错误则返回ERROR)
// 找到了FindMinDist
totalWeight += Dist[V]; // 增加最小生成树总权值
Dist[V] = 0; // 标记V已收录
VCount++; // 更新已收录顶点数
// 打印收录边E
cout << Parent[V] << ' ' << V << '\n';
// 更新V的邻接点的Dist和Parent
W = Graph->G[V].FirstEdge; // W为V的邻接点
while (W != NULL) { // 遍历V的邻接点W
if (Dist[W->AdjV] != 0 && W->Weight < Dist[W->AdjV]) {
// 如果该邻接点W未收录,且W到当前顶点V的距离更小
// W的父结点为V
Dist[W->AdjV] = W->Weight; // 更新Dist[W] 为VW的距离W->Weight
Parent[W->AdjV] = V; // 更新Parent
}
W = W->Next;
}
}
// 检查是否生成完整的最小生成树(顶点数是否等于原图)
if (VCount != Graph->Nv) {
return ERROR;
}
return totalWeight;
}
int main(int argc, char *argv[]) {
LGraph Graph, MST;
WeightType ToltalWeight;
Graph = BuildGraph(); // 读入数据,建立以邻接表为存储结构的图
ToltalWeight = Prim(Graph, &MST); // 构建最小生成树MST,并返回总权值
cout << ToltalWeight << endl;
}
1614

被折叠的 条评论
为什么被折叠?



