CF1242B. 0-1 MST 题解 并查集
题目链接:https://codeforces.com/problemset/problem/1242/B
题目大意:
给定一个包含 个节点的完全图,图中有 条长度为 的边(),其余的边长度均为 。求最小生成树长度。
解题思路(参考自 官方题解 ):
首先,如果只考虑图中长度为 的边的话:假设所有节点和长度为 的边构成的子图中有 个连通块,则最小生成树的长度为 (因为这 个连通块之间需要 条长度为 的边将其连通)。因此,我们的主要目的就是去寻找存在多少个这样的连通块。
下面描述的是一个 的解法。
我们使用并查集维护零权值连通块,同时存储每个连通块的大小。然后从 到 依次遍历每个节点 ,并将节点 放到一个大小为 的连通块内。然后我们遍历与节点 邻接的所有权值为 的边 (要求 )。对于每一个零权值连通块,我们计算从这个连通块(即 所处的连通块)到节点 存在多少条边。如果边的数量小于 所处的连通块的大小,我们需要合并节点 和 (因为在连通块和 之间至少有一条权值为 的边)。否则,我们不能将这个连通块和节点 合并。最后,我们得到了零权值连通块的个数。
这个算法的时间复杂度是多少呢?整体来说,有 个连通块被创造出来了(因为每处理一个节点就会新建一个大小为 的连通块)。当我们将某个老的连通块同节点 进行合并的时候,连通块的数量减少了一个。所以合并操作最多进行 次,而我们是使用并查集来进行合并的,所以这部分的时间复杂度为 。
如果一个旧的连通块与节点 不进行合并,则我们能证明这个旧的连通块节节点 之间至少存在一条边,所以这种情况等于边的数量 —— 。所以这部分的时间复杂度为 。
所以总的时间复杂度为 。
示例程序:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
int n, m, f[maxn], sz[maxn], ans;
vector<int> g[maxn], vec;
map<int, int> cnt;
void init() {
for (int i = 1; i <= n; i++)
f[i] = i, sz[i] = 1;
}
int find(int x) {
return x == f[x] ? x : f[x] = find(f[x]);
}
void merge(int x, int y) {
int a = find(x), b = find(y);
if (a > b) swap(a, b);
if (a != b) f[b] = a, sz[a] += sz[b];
}
int main() {
cin >> n >> m;
init();
while (m--) {
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
for (int u = 1; u <= n; u++) {
cnt.clear(); // cnt[i]记录u与第i个集合有多少相连的边
for (auto v : g[u])
if (v < u)
cnt[find(v)]++;
for (auto v : vec) {
int p = find(v);
if (sz[p] > cnt[p])
merge(p, u);
}
if (find(u) == u) vec.push_back(u);
}
for (int i = 1; i <= n; i++)
if (find(i) == i)
ans++;
cout << ans - 1 << endl;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构