kruskal和prim算法是用来求最小生成树的算法,那什么是最小生成树呢?
最小生成树是一副连通加权无向图中一棵权值最小的生成树,也就是图中包含全部节点且权值和最小的连通子图。
对于kruskal和prim算法的讲解这里有个秒懂视频,讲解的很详细,可以参考下。
kruskal和prim算法秒懂视频
步骤:
N-1
条边为止// 针对的对象:无向连通图
// 返回最小连通图的路径值和
const int MAX_E = 8;
const int MAX_V = 6;
struct edge { int u, v, cost; }; // 表示边e=(u, v), 权值为cost
edge es[MAX_E];
bool cmp(const edge& e1, const edge& e2)
{
return e1.cost < e2.cost;
}
int kruskal()
{
sort(es, es + MAX_E, cmp); // 按照edge.cost的顺序从小到大排列
UF uf(MAX_V); // 实例化并查集
int res = 0;
for (int i = 0; i < MAX_E; i++) // 如果已经加入n-1条边了就可以退出了
{
edge e = es[i];
if (!uf.connected(e.u, e.v)) // 判断u和v是否在同一连通块,如果连通的话该边的加入就会导致出现环
{
uf.unioned(e.u, e.v); // 连接u和v
res += e.cost;
}
}
return res;
}
算法本质:贪心算法
适用类型:稀疏图(对边的操作较多)
时间复杂度:O(NlogN)
步骤:
const int MAX_V = 6;
int cost[MAX_V][MAX_V] = {
{0,4,2,INT_MAX,INT_MAX,INT_MAX},
{4,0,1,3,INT_MAX,INT_MAX},
{2,1,0,5,1,INT_MAX},
{INT_MAX,3,5,0,2,1},
{INT_MAX,INT_MAX,1,2,0,INT_MAX},
{INT_MAX,INT_MAX,INT_MAX,1,INT_MAX,INT_MAX}
}; // cost[u][v]表示边e=(u,v)的权值(不存在的情况下设为INF )
int mincost[MAX_V]; // 保存连接两个区域的边的最小权值
int parent[MAX_V]; // 节点i的父节点
bool vis[MAX_V]; // 顶点i是否包含在集合中
int prim(int s = 0)
{
// 初始化
for (int i = 0; i < MAX_V; i++)
{
mincost[i] = INT_MAX;
vis[i] = false;
}
mincost[s] = 0;
vis[s] = true;
int sumcost = 0;
int v = s; // 表示新加入的结点,注意:后面导致mincost和parent更新的原因就是因为新节点v的加入
while (true)
{
// 1. 更新连接两个区域边的信息(update)
for (int i = 0; i < MAX_V; i++)
{
if (!vis[i] && cost[v][i] < mincost[i])
{
mincost[i] = cost[v][i]; // 更新连接两个区域的边的最小权值
parent[i] = v; // 更新父节点
}
}
// 2. 找连接两个区域的最小权边上的没有访问的顶点(scan)
v = -1;
for (int i = 0; i < MAX_V; i++)
{
if (!vis[i] && (v == -1 || mincost[v] > mincost[i])) v = i;
}
if (v == -1) break; // 所有的节点被访问
// 3. 添加节点到集合(add)
vis[v] = true;
sumcost += mincost[v];
}
return sumcost;
}
算法本质:动态规划算法
适用类型:稠密疏图(对顶点的操作较多)
时间复杂度:O(N^2)
该算法还可以用堆优化,时间复杂度为O(NlogN)