CFP600F 二分图边染色 学习笔记

CFP600F_1 二分图边染色 学习笔记

Luogu Link

前言

题如其名,二分图边染色板子。

这种板子怎么洛谷才过了这么点人?

本题解基本借鉴这篇题解

题意简介

给定一个简单无向二分图。现在将其每一条边染色,使得任意两条有公共顶点的边颜色不同。问最少需要多少种颜色,并给出一种染色方案。

做法解析

是啊,最少需要多少种颜色呢?

首先下界显然是所有点中的最大度数。接下来我们构造一种必定能取到下界的方案。

对于边 \((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\)……这个过程是可以递归下去的。

pEdrm6g.md.png

正确性?我们这样交替染色,不可能有环——因为二分图上环长必为偶数,如果有环的话我们成环的最后一条边肯定染的是 \(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;
}

反思总结

板子,记。

posted @ 2025-03-18 13:52  矞龙OrinLoong  阅读(38)  评论(0)    收藏  举报