图的最小生成树 Kruskal
思路:让边的总长度之和最短,首先选择最短的边,其次选择次短的……,直到选择了n-1条边为止。(注意选边不能造成回路)
难实现的是:判断两个顶点是否已经连通。(可以使用广搜或者深搜,但这样效率低)可以使用已经学习的并查集,把所有的顶点放到并查集中,判断两个顶点是否连通,只需判断两个顶点是否在同一个集合(即是否有共同的祖先)即可,这样时间复杂度为 O ( l o g N ) O(logN) O(logN)。
Kruskal:首先按照边的权值进行从小到大排序,每次从剩余的边中选择权值较小且边的两个顶点不在同一个集合的边(就是不会产生回路的边),加入到生成树中,直到加入了n-1条边为止。
时间复杂度分析:对顶点进行快排的时间复杂度是 O ( N l o g N ) O(NlogN) O(NlogN),对边进行快排的时间复杂度是 O ( M l o g M ) O(MlogM) O(MlogM),在m条边中找到n-1条边的时间复杂度是 O ( M l o g N ) O(MlogN) O(MlogN),所以Kruskal算法的时间复杂度是 O ( M l o g M + M l o g N ) O(MlogM+MlogN) O(MlogM+MlogN),因为M通常比N大,所以最终时间复杂度是 O ( M l o g M ) O(MlogM) O(MlogM)。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
using namespace std;
struct edge
{
int u;
int v;
int w;
};
const int N = 110;
int n, m, a[N];
edge node[N];
void init()
{
memset(a, 0, sizeof(a));
for(int i = 1; i <= n; i++)
a[i] = i