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;
}
posted @ 2024-04-26 17:05  胖柚の工作室  阅读(100)  评论(0)    收藏  举报