学习目标:
- 一天时间掌握kruskal, prim算法原理及模板
学习内容:
-
prim算法实现原理
-
prim模板
-
kruskal算法实现原理
-
kruskal模板
前言:
不到2小时就AK今天上午比赛,但今天的东西终究只是皮毛,于是自己又找了些类型题做做,明天希望做难题时也能灵光乍现。
prim算法实现原理
假设G=(V,E)是连通的,TE是G上最小生成树中边的集合。算法从U={u0}(u0∈V)、TE={}开始。重复执行下列操作:
在所有u∈U,v∈V-U的边(u,v)∈E中找一条权值最小的边(u0,v0)并入集合TE中,同时v0并入U,直到V=U为止。
此时,TE中必有n-1条边,T=(V,TE)为G的最小生成树。
Prim算法的核心:始终保持TE中的边集构成一棵生成树
STEP:
选取任意起点,依次找权值最小的边。
类似于dijkstra的蓝白点阵营思想。
prim模板(堆优化)
int queue_prim (int s,int n) {
int res = 0;
vis[s] = 1;
for(int i = id[s];i;i = e[i].pre)
q.pnowsh(e[i]);
for(int i = 1;i < n;i++){
if(q.size() == 0)break;
node now = q.top();
q.pop();
if(vis[now.to] == 1){
while(vis[now.to]){
now = q.top();
q.pop();
}
}
res += now.cost;
vis[now.to] = 1;
for(int j = id[now.to];j;j = e[j].pre){
if(!vis[e[j].to])q.push(e[j]);
}
}
return res;
}
kruskal算法实现原理
说白了就是按照权值从小到大的顺序选择 n-1 条边,并保证这 n-1 条边不构成回路,首先构造一个只含 n 个顶点的森林,然后依权值从小到大从连通网中选择边加入到森林中,并使森林中不产生回路,直至森林变成一棵树为止。
贪心思想。
kruskal模板
#include <bits/stdc++.h>
using namespace std;
int fa[500005];
long long ans = 0;
int n, m;
struct node {
int x, y, z;
} a[500005];
int Find(int x) {
if (fa[x] == x)
return x;
else
return fa[x] = Find(fa[x]);
}
bool cmp(node a, node b) { return a.z < b.z; }
int main() {
cin >> n >> m;
for (int i = 1; i <= n + 5; i++) {
fa[i] = i;
}
for (int i = 1; i <= m; i++) {
cin >> a[i].x >> a[i].y >> a[i].z;
}
sort(a + 1, a + m + 1, cmp); // 按权值从小到大排序
for (int i = 1; i <= m; i++) {
int b = Find(a[i].x);
int c = Find(a[i].y);
if (b != c)
fa[b] = c, ans += a[i].z;
}
cout << ans;
}
小结
知识的巩固需要时间,明天也要继续加油(ง •_•)ง。