【学习笔记】图上问题

Vizing 定理

图染色问题的经典结论

图染色定义

称一个边染色方案合法当且仅当每个顶点连出的所有边的颜色都互不相同,如果此时出现了 \(k\) 个颜色那么称该方案是图的一组 \(k\) 染色

一张无向图的边着色数为最小的 \(k\) 满足图可以 \(k\) 边染色,但不存在一个 \(k-1\) 边染色方案,记图 \(G\) 的边色数为 \(\chi'(G)\)

同时记 \(\Delta(G)\) 为图上的最大度数

\(\rm{Vizing}\) 定理:

  • 如果满足 \(G\) 是二分图,那么 \(\chi'(G)=\Delta(G)\)

    考虑对这部分进行构造性证明:

    考虑向二分图中加入边 \((x,y)\),设 \(c_x\)\(x\) 点连出的边的颜色中的一个在 \([1,c]\) 中没有出现的颜色,\(c_y\) 同理

    如果 \(c_x=c_y\) 那么直接将这条边染成 \(c_x\) 即可

    否则不妨设 \(c_x< c_y\)\(y\) 点连出的颜色为 \(c_x\) 的边改成颜色 \(c_y\) 并将边 \((x,y)\) 染成 \(c_x\)

    同时由图是二分图,那么一定可以从 \(y\) 点开始找到一条终点不是 \(x\) 的增广路,路径颜色为 \(c_x,c_y\) 交替,直接在 \(\{c_x,c_y\}\) 集合内反色即可

  • 如果 \(G\) 是简单图,那么 \(\Delta(G)\le \chi'(G)\le \Delta(G)+1\)

证明博主不会

例题

Undefined

一张 \((n,m)\) 点的二部图,有 \(k\) 条边,\(c\) 个颜色

一个点的代价是给其边染色之后边表中出现次数最多的颜色减去出现次数最少的颜色,求所有点的代价和的最小值


首先给出结论:\(\rm{Min}=n+m-\sum_{i=1}^{n+m}[c|deg[i]]\)

将一个点的 \(c\) 个边包装成一组进行建立新点,新图仍然是二分图,同时满足每个点的度数 \(\leq c\)

直接使用 \(\rm{Vizing}\) 定理完成结论证明

UOJ44

和上面的题目类似,对于加边操作,动态加虚点找增广路

删边判一下是不是最后一个虚点,不是的话从最后一个点扒一个过来即可

Bron–Kerbosch 算法

求图的最大团,也可以随机化排列贪心加点,随机化算法在n小的时候正确率一次能到 \(3\%\)

BK算法求最大团大小时简单得离谱,直接放代码

const int N=100;
int ans,num[N],sta[N],n,m;
double sum;
inline bool dfs(int now,int x,int res){
    for(int i=x+1;i<=n;++i){
        if(num[i]+res<=ans) break;
        if((sta[i]&now)==now){
            if(dfs(now|1ll<<(i-1),i,res+1)) return 1;
        }
    } if(res>ans) return ans=res,1; return 0; 
}
signed main(){
    n=read(); m=read(); sum=read(); 
    for(int i=1;i<=m;++i){
        int u=read(),v=read();
        sta[u]|=1ll<<(v-1);
        sta[v]|=1ll<<(u-1);
    }
    Down(i,n,1) dfs(1ll<<(i-1),i,1),num[i]=ans;
    print(ans);
    return 0;
}

注意代码短小的同时意味着不能删减任何细节,比如 $ dfs $ 必须有返回值来保证找到就退出

复杂度是 \(\Theta(3^{\frac n3})\),相比于折半再 \(\rm{DP}\) 的做法,空间优秀很多

复杂度的来源是一张图的最大团上界为 \(\Theta(n^{\frac n3})\),比较复杂,论文完全看不懂

上面写的内容是使用BK算法求解最大团的大小,相对复杂的是求解极大团的个数

\(dfs\) 维护三个集合 \(R\):当前最大团集合,\(P\):当前可能加入最大团的集合,\(X\):对于当前 \(R\) 已经被计算过最大团的点的集合

每次找 \(P\) 中找一个和 \(R\) 中所有点相连的点 \(x\)\(R\leftarrow R\cup\{x\},P\leftarrow P\cap N(x),X\leftarrow X\cap N(x)\)

观察到冗余的排除是两个点被加入最大团的顺序是无所谓的,那么对于每个 \(P\) 找到 集合度数\((N(u)\cap P)\) 最大的点作为中枢点,此时能选的点要不是自己,要不是和它不相连的点

对于相连的点,最后统计到包含自己但不包含中枢点的,必然会在不相邻点处被统计;对于包含自己又包含中枢点的情况,在后续的 \(dfs\) 中会作为 \(P\) 中的点被选出来

初始化 \(P=U\)\(P=X=\empty\) 时就找到了一个极大团

posted @ 2021-10-07 19:34  yspm  阅读(407)  评论(0编辑  收藏  举报