传送门:P1330 封锁阳光大学
更佳的阅读体验:洛谷 P1330 题解

阅读本文前,请确保你已经对二分图有所了解。


简要题意:给你一张无向图,求最少选取的节点数量,使得节点之间两两不相邻,且每条边都连接着一个选中节点。

观察给出的条件,发现每个点只有“选”或“不选”两种对立的状态,并且相邻节点的状态必须是不同的。由此我们想到,本题事实上是要求我们判断给定图是否为二分图,因此可以直接染色。

如果染色过程中发现了冲突,说明给定图不是二分图,不论如何也无法得到任何一种合法的方案,此时直接输出 $\texttt{Impossible}$ 并退出程序即可。染色结束后,我们取两种颜色中较少的节点数作为答案即可。

你兴高采烈地写出了一份朴素的二分图染色,然后得到了 50 分的好成绩。

此时你发现,题目给出的限制中,只保证了给定图是一张无向图,而非无向连通图。这样的话,我们就应当对每个连通块进行讨论了。对于每个连通块,我们仍然取两种颜色中较少的节点数,答案即为每个连通块的答案之和。

时间复杂度 $O(n + m)$。

#include <iostream>
#include <algorithm>
using namespace std;

const int N = 1e4 + 10;
int n, m, u, v, col[N], cnt[2], ans;
basic_string<int> g[N];

void dfs(int u, int c) {
    col[u] = c, ++cnt[c];
    for (auto v : g[u]) {
        if (col[v] != -1) {
            if (col[v] == col[u]) {
                cout << "Impossible\n";
                exit(0);
            } continue;
        } dfs(v, c ^ 1);
    }
}

int main() {
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    cin >> n >> m;
    for (int i = 1; i <= m; ++i) {
        cin >> u >> v;
        g[u] += v, g[v] += u;
    } fill(col + 1, col + n + 1, -1);
    for (int i = 1; i <= n; ++i) if (col[i] == -1) {
        cnt[0] = cnt[1] = 0;
        dfs(i, 0);
        ans += min(cnt[0], cnt[1]);
    } cout << ans << '\n';
    return 0;
}
最后修改:2025 年 12 月 31 日
如果觉得我的文章对你有用,请随意赞赏