CFP600F 二分图边染色 学习笔记
CFP600F_1 二分图边染色 学习笔记
前言
题如其名,二分图边染色板子。
这种板子怎么洛谷才过了这么点人?
本题解基本借鉴这篇题解。
题意简介
给定一个简单无向二分图。现在将其每一条边染色,使得任意两条有公共顶点的边颜色不同。问最少需要多少种颜色,并给出一种染色方案。
做法解析
是啊,最少需要多少种颜色呢?
首先下界显然是所有点中的最大度数。接下来我们构造一种必定能取到下界的方案。
对于边 \((u,v)\),设 \(u\) 作为端点的边的颜色集合为 \(C_1\),设 \(v\) 作为端点的边的颜色集合为 \(C_2\)。
此处 \(\text{mex}(S)\) 定义为集合中不存在的最小正整数。设 \(cc1=\text{mex}(C_1),cc2=\text{mex}(C_2)\)。
如果 \(cc1=cc2\) 即存在一种颜色使得 \(C_1,C_2\) 中都不包含且最小,那直接染上去就行了。
如果 \(cc1\neq cc2\),我们还是强制把这条边染成 \(cc1\),但是这样做的话,\(v\) 可能有两条边都是 \(cc1\) 的颜色。设此时另一条颜色为 \(cc1\) 的边为 \((v,w)\),我们把它染成 \(cc2\)。这样的话 \(v\) 也合法了,但是 \(w\) 有可能又不合法了,设此时另一条颜色为 \(cc2\) 的边为 \((w,x)\),则我们把它染成 \(cc1\)……这个过程是可以递归下去的。

正确性?我们这样交替染色,不可能有环——因为二分图上环长必为偶数,如果有环的话我们成环的最后一条边肯定染的是 \(cc2\),其前置条件是成环的最后一个点 \(f\) 存在一条到 \(u\) 的边颜色 \(cc1\),这与 \(u\) 一开始没有颜色为 \(cc1\) 的边矛盾。
然后因为不可能有环,所以一次染色复杂度为 \(O(n)\)。总复杂度 \(O(nm)\le O(n^3)\)。
代码实现
想清楚就很好写。绿题难度。
#include <bits/stdc++.h>
using namespace std;
using namespace obasic;
const int MaxN=2e3+5,MaxM=1e5+5;
int A,B,M,N,X,Y,deg[MaxN],ans;
struct edge{int u,v;}E[MaxM];int tov[MaxN][MaxN];
void addudge(int u,int v,int id){E[id]={u,v},deg[u]++,deg[v]++;}
int main(){
readi(A),readi(B),readi(M),N=A+B;
for(int i=1;i<=M;i++)readi(X),readi(Y),addudge(X,Y+A,i);
for(int i=1;i<=N;i++)maxxer(ans,deg[i]);
for(int i=1,cc1,cc2;i<=M;i++){
auto [u,v]=E[i];cc1=cc2=1;
while(tov[u][cc1])cc1++;
while(tov[v][cc2])cc2++;
tov[u][cc1]=v,tov[v][cc2]=u;
if(cc1==cc2)continue;
for(int tc=cc2,w=v,cx=cc1^cc2;w;){
swap(tov[w][cc1],tov[w][cc2]);
w=tov[w][tc],tc^=cx;
}
}
writi(ans),puts("");
for(int i=1;i<=M;i++){
auto [u,v]=E[i];
for(int j=1;j<=ans;j++){
if(tov[u][j]==v){writi(j),putchar(' ');break;}
}
}
return 0;
}
反思总结
板子,记。
浙公网安备 33010602011771号