一、求最小生成树
题目链接:https://www.luogu.com.cn/problem/P3366
1.prim算法
任意选取一个起点u,设已加入树的结点为V,总结点为T,则每次搜索连接V与T-V的最短边,并使之加入V(即从T-V向V中加入一个新的节点),当T中所有节点访问完成,即为最小生成树。
优先级队列版实现代码:
#include <iostream>
#include <queue>
using namespace std;
#define MK make_pair
const int N = 5003, M = 400050,INF=(1<<30);
int to[M], w[M], nxt[M], tot;//链式前向星
int h[N], dis[N];
bool visit[N];
int n, m;
priority_queue<pair<int, int>> q;
void add(int a, int b, int c) {
to[++tot] = b; //链式前向星加边
w[tot] = c;
nxt[tot] = h[a];
h[a] = tot;
}
void prim() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
dis[i] = INF;
}
for (int i = 1, a, b, c; i <= m; i++) {
cin >> a >> b >> c;
add(a, b, c); add(b, a, c);//无向图加双边
}
q.push(MK(0, 1));
dis[1] = 0;
pair<int, int> now;
int d, u;
while (!q.empty()) {
now = q.top(); q.pop();
d = -now.first; u = now.second; //默认最大堆,所以插入负权值,确保堆顶为最小权值
if (dis[u]<d) continue;//已更新过最小权值,舍弃
visit[u] = true;
for (int i = h[u], v; v = to[i]; i = nxt[i]) {
if (dis[v] > w[i] && !visit[v]) {
dis[v] = w[i]; //若枚举的边可使T-V到V的路径变短,更新
q.push(MK(-dis[v], v));
}
}
}
int ans = 0;
for (int i = 1; i <= n; i++) {
if (dis[i] == INF) {
cout << "orz"; return;
}
ans += dis[i