最小生成树的图对应的图都是无向图,最小生成树没有自环
稠密图用朴素版的Prim算法,O(n ^ 2)
稀疏图用堆优化版的Prim算法,O(m log n)
Kruskal算法,O(m log m)和O(m log n)级别一样,m < n ^ 2,先对所有边从小到大排序
如何选择:
稠密图直接朴素版的Prim算法
稀疏图Kruskal算法
堆优化版的Prim算法一般不常用
二分图:
如何判断一个图是不是二分图:dfs,染色法,O(n + m)
匈牙利算法:求二分图的最大匹配,最坏O(nm),一般远小于
先讲朴素版的Prim算法
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N = 510, INF = 0x3f3f3f3f; 4 int g[N][N]; //邻接矩阵 5 int dist[N]; 6 bool st[N]; 7 int n, m; 8 int prim() { 9 memset(dist, 0x3f, sizeof dist); //初始化距离 10 int res = 0; //最小生成树里所有边的长度之和 11 for (int i = 0; i < n; i++) { //n次迭代 12 int t = -1; 13 for (int j = 1; j <= n; j++) { 14 if (!st[j] && (t == -1 || dist[t] > dist[j])) { 15 t = j; 16 } 17 //t == -1表示如果还没有找到一个点 18 } //找到不在集合当中的,距离最近的点 19 //集合的意思是:当前的生成树,当前的这个连通块 20 //集合S表示,当前已经在连通块中的所有的点 21 if (i && dist[t] == INF) { //如果不是第一个点的话 22 return INF; //不连通的话,不存在最小生成树 23 } 24 if (i) { //只要不是第一个点 25 res += dist[t]; 26 } //先加进去再更新 27 for (int j = 1; j <= n; j++) { //更新距离 28 dist[j] = min(dist[j], g[t][j]); //这个点到集合的距离 29 } 30 st[t] = true; 31 } 32 return res; 33 } 34 int main() { 35 cin >> n >> m; 36 memset(g, 0x3f, sizeof g); 37 while (m--) { 38 int a, b, c; 39 cin >> a >> b >> c; 40 g[a][b] = g[b][a] = min(g[a][b], c); //重边只留最小边 41 } 42 int t = prim(); 43 if (t == INF) { 44 cout << "impossible" << endl; 45 } else { 46 cout << t << endl; 47 } 48 return 0; 49 }