洛谷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;
}
浙公网安备 33010602011771号