洛谷P11022 「LAOI-6」Yet Another Graph Coloration Problem 题解 边双连通分量

题目链接:https://www.luogu.com.cn/problem/P11022

解题思路:

一个可以 AC 的策略:

首先,如果图不连通,则无解。

  • 因为此时肯定得有一个连通块中有白点,同时另一个连通块有黑点,它们之间无法到达。

其次,如果所有的边双连通分量的大小均为 \(1\),则无解(后来我们先,因为 \(n \ge 2\),所以如果图连通的情况下,这种情况其实不会出现、)。

  • 因为此时(这个图是一棵树或森林)任意两点之间要么不连通,要么只有一条简单路径,所以颜色必须相同。

其次,如果图连通且存在一个大小大于 \(1\) 的边双连通分量。则:

我们只需要在这个大小 \(\gt 1\) 的边双连通分量重任选一个不与任何桥相邻的点 \(x\) 染成黑色即可,该双连通分量重的其他点染成白色,然后:

将所有 \(x\) 和同一个连通分量中的点连接的边都删掉,变量两个连通块。

  • \(x\) 所在的连通块都染成黑色;
  • 另一个连通块都染成白色。

示例程序:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5;

int T, n, m, dfn[maxn], low[maxn], ts, bl[maxn], dcc, x, sz[maxn]; // x表示要染成黑色的那个点
bool vis[maxn];
vector<int> g[maxn];
stack<int> stk;
char color[maxn];

void init() {
    for (int i = 1; i <= n; i++) {
        g[i].clear();
        dfn[i] = low[i] = sz[i] = 0;
        vis[i] = false;
    }
    ts = dcc = x = 0;
    while (!stk.empty())
        stk.pop();
    fill(color, color+n+1, 'W');
    color[n+1] = 0;
}

void tarjan(int u, int p) {
    dfn[u] = low[u] = ++ts;
    stk.push(u);
    for (auto v : g[u]) {
        if (v == p) continue;
        if (!dfn[v]) {
            tarjan(v, u);
            low[u] = min(low[u], low[v]);
        }
        else low[u] = min(low[u], dfn[v]);
    }
    if (low[u] == dfn[u]) {
        dcc++;
        int v;
        do {
            v = stk.top();
            stk.pop();
            bl[v] = dcc;
            sz[dcc]++;
        } while (u != v);
    }
}

void dfs(int u) {
    if (vis[u]) return;
    vis[u] = true;
    color[u] = 'B';
    for (auto v : g[u])
        dfs(v);
}

void cal() {
    tarjan(1, -1);
    if (ts < n) { // 图不连通
        puts("-1");
        return;
    }
    for (int i = 1; i <= dcc; i++) {
        if (sz[i] > 1) {
            for (int j = 1; j <= n; j++) {
                if (bl[j] == i) {
                    if (!x) x = j;
                    else vis[j] = true;
                }
            }
            break;
        }
    }
    if (!x) {
        puts("-1");
        return;
    }
    dfs(x);
    puts(color+1);
}

int main() {
    scanf("%d", &T);
    while (T--) {
        scanf("%d%d", &n, &m);
        init();
        for (int i = 0, u, v; i < m; i++) {
            scanf("%d%d", &u, &v);
            g[u].push_back(v);
            g[v].push_back(u);
        }
        cal();
    }
    return 0;
}
posted @ 2025-12-10 03:36  quanjun  阅读(5)  评论(0)    收藏  举报