1 条题解

  • 0
    @ 2026-5-4 20:34:08

    核心思路

    1. 判断图是否为二分图
    2. 若图不是二分图(存在奇环),Alice 有必胜策略:
      永远给出颜色 12。此时 Bob 只能用 12 染色,整个染色相当于一种二染色。但非二分图无法用两种颜色正常染色,必然会出现同色边。因此 Alice 必胜。
    3. 若图是二分图,Bob 有必胜策略。将顶点划分为两个独立集 LLRR,Bob 按以下规则选择:
      • 如果给出颜色包含 11LL 还有未染色点,则选 LL 中点染 11
      • 否则如果包含 22RR 还有未染色点,则选 RR 中点染 22
      • 否则(只能选 33 或一侧已满)选择还有未染色点的那一侧,染 33。 该策略可保证最终所有边两端颜色不同(LL 中只会有 1,31,3RR 中只会有 2,32,3,且不会出现 33-33 边)。

    实现细节

    • 用 BFS/DFS 判定二分图,记录每个点的集合(0 或 1)。
    • 若为非二分图:输出 Alice,之后每轮输出 1 2,然后读取交互器返回的任意值(忽略)。
    • 若为二分图:输出 Bob,接收到两个颜色后按上述规则选择顶点和颜色。

    时间复杂度 O(n+m)O(n+m),完全满足要求。

    参考代码

    #include <bits/stdc++.h>
    using namespace std;
    
    vector<int> getBipartition(int n, const vector<pair<int,int>>& edges) {
        vector<vector<int>> adj(n+1);
        for (auto [u, v] : edges) {
            adj[u].push_back(v);
            adj[v].push_back(u);
        }
        vector<int> side(n+1, -1);
        for (int i = 1; i <= n; ++i) {
            if (side[i] == -1) {
                queue<int> q;
                q.push(i);
                side[i] = 0;
                while (!q.empty()) {
                    int u = q.front(); q.pop();
                    for (int v : adj[u]) {
                        if (side[v] == -1) {
                            side[v] = side[u] ^ 1;
                            q.push(v);
                        } else if (side[v] == side[u]) {
                            return {}; // 不是二分图
                        }
                    }
                }
            }
        }
        return side;
    }
    
    void solve() {
        int n, m;
        cin >> n >> m;
        vector<pair<int,int>> edges(m);
        for (int i = 0; i < m; ++i) {
            cin >> edges[i].first >> edges[i].second;
        }
    
        vector<int> side = getBipartition(n, edges);
        bool bipartite = !side.empty();
    
        if (!bipartite) {
            cout << "Alice" << endl;
            for (int i = 0; i < n; ++i) {
                cout << "1 2" << endl;
                int v, c;
                cin >> v >> c; // 忽略交互器的选择
            }
        } else {
            cout << "Bob" << endl;
            vector<int> L, R;
            for (int i = 1; i <= n; ++i) {
                if (side[i] == 0) L.push_back(i);
                else R.push_back(i);
            }
            for (int i = 0; i < n; ++i) {
                int a, b;
                cin >> a >> b;
                int v = -1, c = -1;
                if ((a == 1 || b == 1) && !L.empty()) {
                    v = L.back(); L.pop_back(); c = 1;
                } else if ((a == 2 || b == 2) && !R.empty()) {
                    v = R.back(); R.pop_back(); c = 2;
                } else if (!L.empty()) {
                    v = L.back(); L.pop_back(); c = 3;
                } else {
                    v = R.back(); R.pop_back(); c = 3;
                }
                cout << v << ' ' << c << endl;
            }
        }
    }
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int t;
        cin >> t;
        while (t--) solve();
        return 0;
    }
    
    • 1

    信息

    ID
    6821
    时间
    2000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    15
    已通过
    1
    上传者