最小生成树
1.prim
每次循环都访问一个点,并将此点所有边找到其最小的边权,如果最小边权对应的点没有被访问过,则加入队列。这相当于向生成树中添加了n-1条最小边,最后检查所有点的连通性,联通的话得到的就是最小生成树,属于贪心算法。
暴力贪心的话复杂度为o(n²),这边采用堆优化的方法,时间复杂度o(mlogn)
const int N = 2e5 + 10, INF = 0x3f3f3f3f3f3f3f3f; int dis[N]; bool vis[N]; int n, m, sum; vector<pair<int, int>> vt[N]; priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int,int>>> q; int prim(int pos) { int ans = 0; int cnt = 0; q.push(make_pair(0, pos)); while (!q.empty() && cnt <= n) { int x = q.top().first; int y = q.top().second; q.pop(); if (vis[y])continue; vis[y] = true; ans += x; cnt++; for (auto it : vt[y]) if (!vis[it.first]) q.push(make_pair(it.second, it.first)); } return ans; } void solve() { cin >> n >> m; memset(dis, INF, sizeof(dis)); for (int i = 1; i <= m; i++) { int u, v, w; cin >> u >> v >> w; vt[u].push_back(make_pair(v, w)); vt[v].push_back(make_pair(u, w)); } int value = prim(1); int flag = 0; for (int i = 1; i <= n; i++) if (!vis[i])flag = 1; if (value >= INF || flag)cout << "orz" << endl; else cout << value << endl; }
跟最短路的代码有些相似。
2、kruskal
将所有边进行排序后利用并查集将点连成一个集合,最后检查一下所有点是否在同一个集合内,是的话则输出最小生成树。
const int N = 2e5 + 10, INF = 0x3f3f3f3f3f3f3f3f; int f[N]; int n, m, sum; struct edge { int u, v, w; }ed[N]; void start() { for (int i = 1; i <= n; i++)f[i] = i; } bool cmp(edge k, edge l) { return k.w < l.w; } int find(int x) { if (x == f[x])return x; f[x] = find(f[x]); return f[x]; } int kruskal() { int ans = 0; int cnt = 0; for (int i = 1; i <= m; i++){ int fu = find(ed[i].u); int fv = find(ed[i].v); if (fu != fv) { f[fu] = fv; ans += ed[i].w; cnt++; } if (cnt == n - 1)return ans; } return -1; } void solve() { cin >> n >> m; start(); for (int i = 1; i <= m; i++) cin >> ed[i].u >> ed[i].v >> ed[i].w; sort(ed + 1, ed + 1 + m, cmp); int temp = kruskal(); int cnt = 0; for (int i = 1; i <= n; i++) if (f[i] == i)cnt++; if (cnt > 1)temp = -1; if (temp != -1)cout << temp << endl; else cout << "orz" << endl; }

浙公网安备 33010602011771号