一、引入:
1、生成树: 所有顶点均由边连接在一起,但不存在回路的图
最小生成树(Minimum Spanning Tree) 即权值和最小的生成树。
2、MST性质 (Minimum Spanning Tree)
二、Prim算法
算法思路:
首先就是从图中的一个起点a(这里假设是1)开始,把a加入U集合,然后,寻找从与a有关联的边中,权重最小的那条边并且该边的终点b(这里是3)在顶点集合:(V-U)中,我们也把b(3)加入到集合U中,并且输出边(a,b)的信息,这样我们的集合U就有:{a,b},然后,我们寻找与a关联和b关联的边中,权重最小的那条边并且该边的终点在集合:(V-U)中,我们把c(6)加入到集合U中,并且输出对应的那条边的信息,这样我们的集合U就有:{a,b,c}这三个元素了,一次类推,直到所有顶点都加入到了集合U。
完整代码如下:
#include <iostream>
using namespace std;
const int N = 6;
#define INF 0x3f3f3f3f //无穷大
int c[N + 1][N + 1] = {{0},
{0, INF, 6, 1, 5, INF, INF},
{0, 6, INF, 5, INF, 3, INF},
{0, 1, 5, INF, 5, 6, 4},
{0, 5, INF, 5, INF, 5, 2},
{0, INF, 3, 6, INF, INF, 6},
{0, INF, INF, 4, 2, 6, INF}
};
void Prim(int n) {
int lowcost[N + 1]; //记录c[j][closest]的最小权值
int closet[N + 1]; // V-S中点j在S中的最邻接顶点
bool s[N + 1];
s[1] = true; //选择1作为起点
//初始化s[i],lowcost[i],closest[i]
for (int i = 2; i <= n; i++) {
lowcost[i] = c[1][i];
closet[i] = 1;
s[i] = false;
}
for (int i = 1; i < n; i++) {
int min = INF;
int j = 1; //邻接点
for (int k = 2; k <= n; k++) {
//找出V-S中使lowcost最小的顶点j
if (lowcost[k] < min && !s[k]) {
min = lowcost[k];
j = k;
}
}
cout << j << " " << closet[j] << endl;
s[j] = true; //将j添加到S中
for (int k = 2; k <= n; k++) {
//将j添加到S中后,修改closest和lowcost的值
if (c[j][k] < lowcost[k] && !s[k]) {
lowcost[k] = c[j][k];
closet[k] = j;
}
}
}
}
int main() {
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= N; j++) {
if (c[i][j] != INF)
cout << c[i][j] << "\t";
else
cout << "∞\t";
}
cout << endl;
}
cout << "Prim选边过程为:" << endl;
Prim(N);
return 0;
}
三、kruskal算法
1、基本思想:
首先将G的n个顶点看成n个孤立的连通分支,将所有的边按权从小到大排序;然后从第一条边开始,依边权递增的顺序查看每条边,并按下述方法连接两个不同的连通分支:
- 当查看到第k条边(v,w)时,如果端点v和w分别是当前两个不同的连通分支T1和T2中的顶点时,就用边(v,w)将T1和T2连接成一个连通分支,然后继续查看第k+1条边;
- 如果端点v和w在当前的同一个连通分支中,就直接再查看第k+1条边。
这个过程一直进行到只剩下一个连通分支时为止。此时,这个连通分支就是G的一颗最小生成树。