最小生成树 (学习笔记)(25.11.18)
最小生成树 (学习笔记)
概述
在一个图中,边权最小的生成树,称为最小生成树
实现
Kruskal 算法
是一种贪心算法,先把每个边的边权进行排序,然后用并查集维护一下某两个点连接的信息
#include <bits/stdc++.h>
using namespace std;
const int N = 1e3*5+10;
int n, m, ans=0;
struct edge {
int u, v, w;
}s[200100];
int fa[N];
int find(int x) {
if (fa[x]==x) return x;
return find(fa[x]);
}
void add_f(int x, int y) {
if (fa[x]==fa[y]) return;
x = find(x), y = find(y);
fa[x] = y;
}
bool cmp(edge a, edge b) {
return a.w<b.w;
}
int main() {
cin>>n>>m;
for (int i=1; i<=n; i++) fa[i]=i;
for (int i=1; i<=m; i++) {
int x, y, z;
cin>>x>>y>>z;
s[i] = {x,y,z};
// add(x,y,z), add(y,x,z);
}
sort(s+1, s+m+1,cmp);
for (int i=1; i<=m; i++) {
if (find(s[i].u)!=find(s[i].v)) {
add_f(s[i].u,s[i].v);
ans+=s[i].w;
}
}
for (int i=1; i<n; i++) {
if (find(i)!=find(i+1)) {
cout<<"orz";
return 0;
}
}
cout<<ans;
return 0;
}
prim算法
其实现是从一个点开始加点,而不是Kruskal的加边,实现如下
每一次去选择一个距离最小的节点,然后用新的边去做维护,(与Dij很像)我在S组好像当场创造了这个玩意
#include <bits/stdc++.h>
using namespace std;
const int N = 1e3*5+100;
const int M = 1e5*2+100;
int n, m;
int h[N], cnt=1;
struct edge {
int to, nxt, w;
}s[M*2];
void add(int u, int v, int w) {
s[++cnt] = {v,h[u],w};
h[u] = cnt;
}
struct Edge {
int u, w;
bool operator <(const Edge& k) const {return w>k.w;}
};
priority_queue<Edge> q;
bool vis[N];
int ans=0, ans_o=0;
void prim(int x) {
q.push({x,0});
while (!q.empty()) {
int u = q.top().u;
int w = q.top().w;
q.pop();
if (vis[u]) continue;
vis[u]=1;
ans+=w;ans_o++;
for (int i=h[u]; i!=0; i=s[i].nxt) {
int v = s[i].to, w = s[i].w;
if (!vis[v]) {
q.push({v,w});
}
}
}
}
int main() {
cin>>n>>m;
for (int i=1; i<=m; i++) {
int x, y, z;
cin>>x>>y>>z;
add(x,y,z), add(y,x,z);
}
prim(1);
if (ans_o!=n) cout<<"orz";
else cout<<ans;
return 0;
}

浙公网安备 33010602011771号