CF830E Perpetual Motion Machine

空気力学の詩發表於2024-08-14

一堆 Cornner Case 的大分討,我們全隊一邊寫一邊補情況,WA 了五發終於幹過去了

首先當圖中存在某個環時,我們只要給環上的所有點賦值為 \(1\) 即可;又因為圖連通所以只要考慮樹的情況即可

考慮如果存在一個度數 \(\ge 4\) 的點,將其賦值為 \(2\) 並將其周圍的四個點賦值為 \(1\) 即可

如果存在兩個及以上度數為三的點,只要將其中兩個的路徑上所有點賦值為 \(2\),並在端點處各選兩個點賦值為 \(1\) 即可

難點在於有且僅有一個度數為三的點的情況,因為我們很容易證明一條鏈的情況是無解的

考慮此時的圖一定形如一箇中心點,往外延申出三條鏈,不妨將這三條鏈的長度記為 \(a,b,c(a\le b\le c)\)

考慮找出一些最小的有解結構,方法可以是人類智慧也可以是爆搜,最後發現以下三種 Case 是合法的:

然後這題就做完了,判斷一個圖是否滿足上述條件即可,程式碼是徐神寫的

#include <bits/stdc++.h>

std::vector<int> work() {
    int n, m; std::cin >> n >> m;
    std::vector<std::vector<int>> out(n, std::vector<int>());
    for(int i = 0, f, t; i < m; ++i) {
        std::cin >> f >> t;
        f--; t--;
        out[f].push_back(t);
        out[t].push_back(f);
    }

    std::vector<int> ans(n, 0);

    std::vector<bool> vis(n, false);
    std::function<bool(int, int)> dfs = [&](int cur, int fa) -> bool {
        vis[cur] = true;
        for(auto out: out[cur]) {
            if(out == fa) continue;
            if(vis[out] || dfs(out, cur))
                return ans[cur] = 1, vis[cur] = true;
        }
        return false;
    };

    for(int i = 0; i < n; ++i) if(!vis[i] && dfs(i, -1)) return ans;

    for(int i = 0; i < n; ++i) if(out[i].size() >= 4) {
        ans[i] = 2;
        for(int j = 0; j < 4; ++j) ans[out[i][j]] = 1;
        return ans;
    }

    auto ahaha = [&](auto self, int cur, int fa) -> int {
        for(auto out: out[cur]) if(out != fa) return self(self, out, cur) + 1;
        return 1;
    };

    auto fill = [&](auto self, int cur, int fa, std::vector<int> val) -> void {
        if(val.empty()) return ;
        ans[cur] = val.back(); val.pop_back();
        for(auto out: out[cur]) if(out != fa) self(self, out, cur, val);
    };
    
    vis.assign(n, false);

    auto dfs2 = [&](auto self, int cur, int fa) -> int {
        vis[cur] = true;
        if(out[cur].size() == 3) return ans[cur] = 2, cur;
        for(auto out: out[cur]) if(out != fa) {
            int res = self(self, out, cur);
            if(res >= 0) return ans[cur] = 2, res;
        }
        return -1;
    };

    bool flag = false;

    for(int i = 0; i < n && !flag; ++i) if(!vis[i] && out[i].size() == 3) {
        vis[i] = true;
        for(auto out: out[i]) {
            if(flag) break;
            int res = dfs2(dfs2, out, i);
            // std::cerr << "res = " << res << char(10);
            if(res >= 0) {
                ans[i] = 2;
                flag = true;
            }
        }
    }

    if(flag) {
        for(int i = 0; i < n; ++i) if(ans[i] == 2) for(auto out: out[i]) if(ans[out] == 0) ans[out] = 1;
        return ans;
    }

    for(int i = 0; i < n; ++i) if(out[i].size() == 3) {
        std::pair<int, int> len[3];
        for(int j = 0; j < 3; ++j) len[j] = {ahaha(ahaha, out[i][j], i), out[i][j]};
        std::sort(len, len + 3);
        // std::cerr << "len[] = [";
        // for(int j = 0; j < 3; ++j) std::cerr << len[j].first << (j == 2 ? "]\n" : ", ");
        if(len[0].first >= 2 && len[1].first >= 2 && len[2].first >= 2) {
            ans[i] = 3;
            fill(fill, len[0].second, i, std::vector<int>{1, 2});
            fill(fill, len[1].second, i, std::vector<int>{1, 2});
            fill(fill, len[2].second, i, std::vector<int>{1, 2});
            return ans;
        }
        if(len[0].first >= 1 && len[1].first >= 2 && len[2].first >= 5) {
            ans[i] = 6;
            fill(fill, len[0].second, i, std::vector<int>{3});
            fill(fill, len[1].second, i, std::vector<int>{2, 4});
            fill(fill, len[2].second, i, std::vector<int>{1, 2, 3, 4, 5});
            return ans;
        }
        if(len[0].first >= 1 && len[1].first >= 3 && len[2].first >= 3) {
            ans[i] = 4;
            fill(fill, len[0].second, i, std::vector<int>{2});
            fill(fill, len[1].second, i, std::vector<int>{1, 2, 3});
            fill(fill, len[2].second, i, std::vector<int>{1, 2, 3});
            return ans;
        }
    }

    return {};
}

int main() {
    std::ios::sync_with_stdio(false);
    int t; std::cin >> t; while(t--) {
        auto ans = work();
        if(ans.empty()) std::cout << "NO\n";
        else {
            std::cout << "YES\n";
            int n = ans.size();
            for(int i = 0; i < n; ++i) std::cout << ans[i] << char(i == n - 1 ? 10 : 32); 
        }
    }
    return 0;    
}

相關文章