從CF1702E看二分圖判斷的兩種方法

加固文明幻景發表於2024-03-12

https://www.luogu.com.cn/problem/CF1702E

轉化題意

把所有數連邊,判斷是否為二分圖。

染色法

void solve() {
    #define tests
    int n;
    std::cin >> n;
    std::map<int, std::vector<int>> edge;
    std::vector<bool> used(n + 1);
    bool ok(true);
    for (int i = 0; i < n; i++) {
        int a, b;
        std::cin >> a >> b;
        edge[a].push_back(b); 
        edge[b].push_back(a);
        if (a == b or sz(edge[a]) > 2 or sz(edge[b]) > 2) {ok = false;}//出現次數大於二
    }

    if (not ok) {NO; return ;}

    auto dfs = [&](auto self, int now) -> int {
        used[now] = true;
        for (auto to : edge[now]) if (not used[to]) {
            return self(self, to) + 1;
        }
        return 1;
    };//其實也是判斷有沒有奇環,顯然總數加起來如果是奇數就是奇環

    for (int i = 0; i < n; i++) {
        if (not used[i + 1] and (dfs(dfs, i + 1) & 1)) {
            ok = false;
        }
    }
    ok ? YES : NO;
}

擴充套件域並查集

//擴充套件域並查集維護是否為二分圖
//構造出x的敵人x+n和y的敵人y+n
//因為是分成兩個集合,所以只要構造一個敵人(即另一個與自己相等的數,但不能放到同一個集合內所以稱為敵人)
//把x和y的敵人合併,y和x的敵人合併
//如果x和自己的敵人在一個並查集,就不合法

void solve() {
    #define tests
    int n;
    std::cin >> n;
    std::vector<int> cnt(n);
    DSU dsu(n * 2);
    for (int i = 0; i < n; i++) {
        int x, y;
        std::cin >> x >> y;
        x--, y--;
        cnt[x]++; cnt[y]++;
        dsu.merge(x, y + n); dsu.merge(x + n, y);
    }
    bool ok(true);
    for (int i = 0; i < n; i++) {
        if (cnt[i] > 2) ok = false;
        if (dsu.find(i) == dsu.find(i + n)) ok = false;
    }
    ok ? YES : NO;
}

相關文章