二分图边染色
无向图的边染色
对无向图
若无向图是
Vizing 定理
对于任意简单图
求解简单图的边染色是 NP-hard 的。一般只考虑二分图的边染色。感兴趣的可以尝试证明上述定理。
二分图的边染色
对于二分图
在此给出的是构造性证明,考虑在动态加边的过程中维护边染色。
加入边
若
否则,不妨假设
注意到如果
故我们一定可以找到这样的一条增广路使之不包含
证毕。
求解二分图的边染色可以按上面的方式进行,注意到增广路的长度为
例题
[CF600F] Edge coloring of bipartite graph
真.模板题。提供一份参考实现。
#include<iostream>
const int N = 2e3+10, M = 1e5+10;
int a, b, m, rs, c1, c2, c[N][N], u[M], v[M], d[N];
int main(){
std::cin >> a >> b >> m; for(int i = 1; i <= m; i++)
std::cin >> u[i] >> v[i], v[i] += a, ++d[u[i]], ++d[v[i]];
for(int i = 1; i <= a+b; i++) rs = std::max(rs, d[i]);
for(int i = 1; c1=1, c2=1, i<=m; i++){
while(c[u[i]][c1]) c1++; while(c[v[i]][c2]) c2++;
c[u[i]][c1] = v[i], c[v[i]][c2] = u[i]; if(c1==c2) continue;
for(int t=c2,w=v[i]; w; w=c[w][t],t^=c1^c2) std::swap(c[w][c1], c[w][c2]);
}
std::cout << rs << '\n';
for(int i = 1; i <= m; i++) for(int j = 1; j <= rs; j++)
if(c[u[i]][j] == v[i]) std::cout << j << ' ';
}
[AGC037D] Sorting a Grid
给定一个
将
将
将
要求
注意到
因此第一次操作只需要给每个元素定一个列,使得每列不会出现同行的元素。易于发现这样一定合法。
建出左右都有
对该图做二分图边染色,颜色相同的边在
复杂度与二分图边染色一致。
P9070 [CTS2023] 琪露诺的符卡交换
给定
注意到“不相交的”没有用,如果某一状态经过置换
考察如果矩阵的每一列都是一个排列,那么转置一定合法。考察其共轭类
发现这样等价于让原矩阵在
于是建图,左部点
然后你发现每个点的度数都是
P10062 [SNOI2024] 拉丁方
给定
考虑
现在考虑
CF212A Privatization
给定二分图
答案的一个显然下界为
将一个点拆为
CF1240F Football
有
如果第
注意到在上一道题构造的方案中,每个点的答案不超过
uoj444 二分图
给定二分图的左右部点集,动态加边删边维护 CF212A 那道题的方案。
不难发现问题在于处理删边,发现删除最后一条和这个点相连的边一定合法,于是我们每次删边将当前边的边集与相连通的最后一条边互换即可。
CF547D Mike and Fish
给定
把点视作边,一个点
考虑如果能找到一个欧拉回路,对回路上的边黑白染色不会让极差增大。所以如果每个点的度数都是偶数,可以很容易的构造。
现在考虑有的点度数为奇数,建立虚点向所有度数为奇数的点连边。注意到无向图的度数和为偶数,所以只有偶数个度数为奇数的点,虚点的度数也为偶数,跑一边欧拉回路构造即可。
CF1499G Graph Coloring
在 CF547D 的条件下动态加边维护染色方案。
我们维护颜色交替出现的,极长的路径/欧拉回路的集合。
考虑对于一条路径,如果加一条边后可以成为环,因为这是个二分图,所以一定是偶环。
“经过一个点的边颜色极差不超过
加入一条边