- B1: 前缀和与差分
- B2: 快速组合
- B3: 二分查找
- B4: 高精度加法
- B4: 高精度除法
- B4: 高精度乘法
- B4: 高精度减法
- D1: 单调栈
- D2: 单调队列
- D3: Spare Table
- D4: 字典树
- D5: 并查集
- D6: 树状数组-限定区间计数
- D6: 树状数组-单点更新区间求和
- D7: 线段树-基础
- G1: 二分图-判定
- G2: 二分图-最大匹配
- G3: Astar k短路 on matrix
- G4: 拓扑排序
- G5: 连通无环无向图的重心
- G6: MST-Kruskal
- G7: MST-Prim
- G8: ShortestPath-BellmanFord
- G9: ShortestPath-Dijkstra
- G9: ShortestPath-Dijkstra Heap OPT
- G10: ShortestPath-SPFA
- G11: ShortestPath-Floyd
- M1: 快速幂与龟速乘
- M2: 欧几里得-最大公约数
- M2: EX欧几里得-翡蜀定理
- M2: EX欧几里得-线性同余方程
- M2: EX欧几里得-乘法逆元
- M3: 费马小定理-乘法逆元
- M4: 分解质因数
- M4: 分解质因数-欧拉函数
- M4: 分解质因数-多数乘积约数计数
- M4: 分解质因数-多数乘积约数求和
- M5: 欧拉筛
- M5: 欧拉筛-质数筛
- M6: 埃氏筛-质数筛
- M7: Stein算法-最大公约数
- M8: 矩阵乘法与快速幂
- O1: 快速排序
- O2: 并归排序
- S1: KMP
- S2: 字符串哈希
template< class type >
class MST_Prim {
const int n;
unordered_set<int> vis;
type dis[maxn+1];
public:
const int INF = numeric_limits<type>::max()>>1u;
int ar[maxn+1][maxn+1] {};
explicit MST_Prim(const int n): n(n) {
for (int i = 1; i <= n; i++) fill(ar[i]+1, ar[i]+n+1, INF);
for (int i = 1; i <= n; i++) ar[i][i] = 0;
}
type solve() {
unordered_set< int >().swap(vis);
for (int i = 1; i <= n; i++) vis.insert(i);
fill(dis+1, dis+n+1, INF);
dis[*vis.begin()] = 0;
for (int k = 0, cur; k < n; k++) {
cur = *vis.begin();
for (const auto i : vis) if (dis[i] < dis[cur]) cur = i;
if (dis[cur] == INF) return INF;
vis.erase(cur);
for (const auto i : vis) dis[i] = min(dis[i], ar[cur][i]);
}
return accumulate(dis+1, dis+n+1, (type)0);
}
};
Notes
- 虽然思想和
Dijkstra基本一致, 但负权边的存在无影响, 可以用等价转换(曲线救国)的思想考虑下 - 易错点:
- 存图时注意处理重边(邻接矩阵通病)
- 算法思路:
- 邻接矩阵存图
- 集合
vis(表示未加入mst的点集)包含所有点,个点到mst距离dis数组(初值为INF) -
dis[任意一个初始点] =0 - 循环n次(第一次循环结束后
dis表示个点到初始点的距离) - 在集合
vis中找到距离mst最近的点cur - 将
cur从集合vis中删除 - 对(连接
mst集合与vis集合的边集)进行更新