2024-04-26 17:05阅读: 20评论: 0推荐: 0

ABC 288 C - Don't be cycle

题目链接:

题目大意:给定一个简单无向图,要求删除最小的边数(可以不删)使得图中没有环。

每增加一条边,看这条边的端点 ab 是否在一个连通块中,在的话就答案 +1(属于废边),否则将连通块合并。

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int p[N];
int find(int x) {
if (p[x] == x) return x;
return p[x] = find(p[x]);
}
int main()
{
ios::sync_with_stdio(false), cin.tie(nullptr);
int n, m, ans = 0;
cin >> n >> m;
for (int i = 1; i <= n; i++) p[i] = i;
for (int i = 1; i <= m; i++) {
int u, v;
cin >> u >> v;
if (find(u) == find(v)) ans++;
else p[find(u)] = find(v);
}
cout << ans;
return 0;
}

另一种思路:要求需要删除的最小边数,我们可以考虑最多可以保留的最大边数。若最多可以保留 t 条边,则输出 mt 即可。

假设图中共有 x 个连通块(点数对应为 xi ),要使图中无环需要将每个连通块都变成一棵树。因此边数之和 = i=1i=xxi1,而 i=1i=xxi=n,因此边数之和=nx,输出 m(nx)

jiangly 的代码:

#include <bits/stdc++.h>
using i64 = long long;
struct DSU {
std::vector<int> f, siz;
DSU(int n) : f(n), siz(n, 1) { std::iota(f.begin(), f.end(), 0); }
int leader(int x) {
while (x != f[x]) x = f[x] = f[f[x]];
return x;
}
bool same(int x, int y) { return leader(x) == leader(y); }
bool merge(int x, int y) {
x = leader(x);
y = leader(y);
if (x == y) return false;
siz[x] += siz[y];
f[y] = x;
return true;
}//如果在一个连通块就返回false,否则合并到一个连通块后返回真
int size(int x) { return siz[leader(x)]; }
};
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n, m;
std::cin >> n >> m;
int comp = n;//初始时每个点都是一个独立的连通块
DSU dsu(n);
for (int i = 0; i < m; i++) {
int u, v;
std::cin >> u >> v;
u--, v--;
comp -= dsu.merge(u, v);
}
std::cout << m - (n - comp) << "\n";
return 0;
}

本文作者:pangyou3s

本文链接:https://www.cnblogs.com/pangyou3s/p/18160462

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   胖柚の工作室  阅读(20)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起