ABC 288 C - Don't be cycle
题目链接:
题目大意:给定一个简单无向图,要求删除最小的边数(可以不删)使得图中没有环。
每增加一条边,看这条边的端点 \(a\)、\(b\) 是否在一个连通块中,在的话就答案 \(+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\) 条边,则输出 \(m-t\) 即可。
假设图中共有 \(x\) 个连通块(点数对应为 \(x_i\) ),要使图中无环需要将每个连通块都变成一棵树。因此边数之和 = \(\sum_\limits{i=1}^{i=x}x_i-1\),而 \(\sum_\limits{i=1}^{i=x}x_i=n\),因此边数之和=\(n-x\),输出 \(m-(n-x)\)。
\(\rm 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;
}

浙公网安备 33010602011771号