#include <iostream>
#include <limits.h>
#include <string> // 包含string以便处理顶点的字符表示
#define MAX_V_NUM 20
using namespace std;
struct closedge
{
char adjvex; // 邻接点的字符表示
int lowcost; // 到邻接点的最小权值
};
closedge shortEdge[MAX_V_NUM]; // 存储候选最短边集
class MGraph
{
private:
char vertex[MAX_V_NUM]; // 图的顶点数组
int arc[MAX_V_NUM][MAX_V_NUM]; // 图的邻接矩阵
int vexNum, arcNum; // 顶点数和边数
public:
MGraph(); // 构造函数
void Prim(int start); // 实现Prim算法
};
MGraph::MGraph()
{
cout << "请输入顶点的个数:";
cin >> vexNum;
cout << "请依次输入" << vexNum << "个顶点的值:" << endl;
for (int i = 0; i < vexNum; i++)
{
cin >> vertex[i];
}
cout << "请输入边的个数:";
cin >> arcNum;
char vi, vj;
int w;
// 初始化邻接矩阵
for (int i = 0; i < vexNum; i++)
{
for (int j = 0; j < vexNum; j++)
{
if(i==j)
{
arc[i][j] =0;
}
else
{
arc[i][j]=INT_MAX;
}
}
}
cout << "请依次输入" << arcNum << "个边的起点、终点和权值:" << endl;
for (int i = 0; i < arcNum; i++)
{
cin >> vi >> vj >> w;
arc[vi - 'A'][vj - 'A'] = w;
arc[vj - 'A'][vi - 'A'] = w; // 因为是无向图
}
// 假设从顶点0开始Prim算法
Prim(0);
}
void MGraph::Prim(int start)
{
// 初始化shortEdge数组
for (int i = 0; i < vexNum; i++)
{
shortEdge[i].lowcost = arc[start][i];
shortEdge[i].adjvex = start;
}
shortEdge[start].lowcost = 0;
cout << "最小生成树是:" << endl;
for (int i = 0; i < vexNum - 1; i++)
{
int k = 0;
for (int j = 0; j < vexNum; j++)
{
if(shortEdge[j].lowcost!=0&&shortEdge[j].lowcost!=INT_MAX){
k=j;
break;
}
}
for (int j = 0; j < vexNum; j++){
if (shortEdge[j].lowcost!=0&&shortEdge[k].lowcost>shortEdge[j].lowcost)
{
k =j;
break;
}
}
// 输出最小边
cout << "(" << vertex[shortEdge[k].adjvex] << vertex[k] << ")" << shortEdge[k].lowcost << endl;
// 将找到的最小边标记为0,表示已访问
shortEdge[k].lowcost = 0;
for (int j = 0; j < vexNum; j++)
{
if (arc[k][j]!=0&&arc[k][j] < shortEdge[j].lowcost)
{
shortEdge[j].lowcost = arc[k][j];
shortEdge[j].adjvex = k;
}
}
}
}
int main()
{
MGraph graph;
return 0;
}
Kruskal算法求最小生成树
【算法思想】
将所有边按照权值的大小进行升序排序,然后从小到大一一判断,条件为:如果这个边不会与之前选择的所有边组成回路,就可以作为最小生成树的一部分;反之,舍去。直到具有 n 个顶点的连通网筛选出来 n-1 条边为止。筛选出来的边和所有的顶点构成此连通网的最小生成树。
注意:排序时如果两条边权值相同,起点下标较小边排在前面,保证测试数据的准确。
判断是否会产生回路的方法
1、标记法:在初始状态下给每个顶点赋予不同的标记,对于遍历过程的每条边,其都有两个顶点,判断这两个顶点的标记是否一致,如果一致,说明它们本身就处在一棵树中,如果继续连接就会产生回路;如果不一致,说明它们之间还没有任何关系,可以连接。 假设遍历到一条由顶点 A 和 B 构成的边,而顶点 A 和顶点 B 标记不同,此时不仅需要将顶点 A 的标记更新为顶点 B 的标记,还需要更改所有和顶点 A 标记相同的顶点的标记,全部改为顶点 B 的标记。