最小生成树笔记1:Kruskal
一、算法原理
kruskal算法是一种基于贪心思想的算法,将每一条边排序,然后从小到大依此选择,能选则选,若不能选则下一个,直到每个点都被选中。其中,有无被选中用并查集来判断。
将每条边看成一棵树,若两个点在同一个边上,则看这两个点是不是在同一个树上,若不是就可以通过这个最小的可以连接这两颗树的边(因为是从小到大选的,所以如果有比它更小的边,则会被提前选中),如此反复就可以找到最小的一棵树。
二、算法模板
int fa[100005];
int n, m;
struct Edge
{
int u, v, w;
friend bool operator<(Edge a, Edge b)
{
return a.w < b.w;
}
} e[500005];
int find(int x)
{
if (fa[x] == 0)
return x;
return fa[x] = find(fa[x]);
}
int solve()
{
int u, v, w, ans = 0;
cin >> n >> m;
for (int i = 1; i <= n; i++)
fa[i] = 0;
for (int i = 1; i <= m; i++)
cin >> e[i].u >> e[i].v >> e[i].w;
sort(e + 1, e + 1 + m);
int cnt = 0;
for (int i = 1; i <= m; i++)
{
int q = find(e[i].u), p = find(e[i].v);
if (p == q)
continue;
cnt++;
ans += e[i].w;
fa[q] = p;
if (cnt == n - 1)
break;
}
return ans;
}
算法总结
时间复杂度和把所有边排序的复杂度一样,为O(mlogm)。
如果只需要求最小生成树的最大边的权值,可以在O(m)的时间内求出。
最小生成树笔记2 :prim
一、算法原理
和dijkstra算法类似都是一个点一个点找最小边长,有所不同的是,prim的dis数组是用来更新最小边,而dijkstra是用来更新最短路径
二、算法模板
int maps[105][105];
int dis[105];
bool bj[105];
int prim(int m)
{
for (int i = 1; i <= m; i++)
dis[i] = 0x3f3f3f3f;
for (int i = 1; i <= m; i++)
bj[i] = 0;
int ans = 0;
for (int i = 1; i <= m; i++)
{
int v = -1;
for (int j = 1; j <= m; j++)
{
if (!bj[j] && (v == -1 || dis[j] < dis[v]))
v = j;
}
if (i != 1 && dis[v] == 0x3f3f3f3f)
return 0x3f3f3f3f;
if (i != 1)
ans += dis[v];
bj[v] = 1;
for (int j = 1; j <= m; j++)
dis[j] = min(dis[j], maps[v][j]);
}
return ans;
}
算法总结
和dijkstra算法差不多,所以复杂度一样都是O(n²)