zoukankan      html  css  js  c++  java
  • Solution -「多校联训」签到题

    (mathcal{Description})

      Link.

      给定二分图 (G=(Xcup Y,E)),求对于边的一个染色 (f:E ightarrow{1,2,dots,c}),最小化每个结点所染颜色数量极差之和。输出这一最小值。

      (|X|+|Y|,|E|le10^6)

    (mathcal{Solution})

      基于“结论好猜”就能认为这题是签到题吗……

      答案显然有下界 (sum_{u}left[c otmid sum_{v}[(u,v)in E] ight])由于写一发过掉了大样例,我们尝试证明它必然可取到。

    证明   **引理(对于二分图的 Vizing 定理):** 对于二分图 $G$,$chi'(G)=Delta(G)$,其中 $chi'(G)$ 为 $G$ 的边染色的色数,$Delta(G)$ 为 $G$ 中结点的最大度数。

      证明: 给出构造。按任意顺序枚举 ((x,y)in E),令 (p)(x) 的邻接边中未染的最小颜色,(q)(y) 的邻接边中未染的最小颜色。由于 (chi'(G)=Delta(G))(p,q) 是存在的。

    1. (p=q),令 (f((x,y))=p)
    2. (p ot=q),不妨令 (p>q),必然存在增广路 (P=lang x_1=x,y_1,x_2,y_2,cdots,x_k ang),满足 (forall iin[1,k),f((x_i,y_i))=pland f((y_i,x_{i+1}))=q)。同时,亦有 (y otin P)。我们翻转这条路径的边染色,即 (f((x_i,y_i))leftarrow q,f((y_i,x_{i+1}))leftarrow p)。此时可套用讨论 1.。

      综上,每条边都能被染色且不出现共色的邻接边。命题得证。 (square)

      尝试将原命题向引理靠拢。令新图 (G') 初始为 (G)。依次枚举 (G') 中的结点 (x),尝试将其拆点。设 (x) 的邻接点集为 (operatorname{adj}(x)),任取它的一个划分 (S={S_1,cdots,S_k}),满足 (|S_1|=cdots=|S_{k-1}|=c),若 (k>1),则令 (V_{G'}leftarrow V_{G'}cup{x_1,cdots,x_k}setminus{x}),且 (operatorname{adj}(x_i)leftarrow S_i)。注意若 (x) 已是拆出的点,那么必然不会导致图的变动,拆点是可完成的。

      此后,发现 (Delta(G')le c)(G') 依旧是二分图。由引理,(chi'(G)=Delta(G)),我们取出这样一个染色 (f),将拆点合并回原图 (G) 且不改变边染色,显然 (f) 取到了答案下界。 (square)

      (mathcal O(|X|+|Y|+|E|)) 算一算就好。

    (mathcal{Code})

    /*~Rainybunny~*/
    
    #ifndef RYBY
    #pragma GCC optimize( "Ofast" )
    #endif
    
    #include <bits/stdc++.h>
    
    #define rep( i, l, r ) for ( int i = l, rep##i = r; i <= rep##i; ++i )
    #define per( i, r, l ) for ( int i = r, per##i = l; i >= per##i; --i )
    
    inline char fgc() {
    	static char buf[1 << 17], *p = buf, *q = buf;
    	return p == q && ( q = buf + fread( p = buf, 1, 1 << 17, stdin ), p == q )
    	   ? EOF : *p++;
    }
    
    inline int rint() {
    	int x = 0, s = fgc();
    	for ( ; s < '0' || '9' < s; s = fgc() );
    	for ( ; '0' <= s && s <= '9'; s = fgc() ) x = x * 10 + ( s ^ '0' );
    	return x;
    }
    
    const int MAXN = 1e6;
    int n, m, k, c, deg[MAXN + 5];
    
    int main() {
    	freopen( "qiandao.in", "r", stdin );
    	freopen( "qiandao.out", "w", stdout );
    	
    	n = rint(), m = rint(), k = rint(), c = rint();
    	rep ( i, 1, k ) {
    		int u = rint(), v = rint();
    		++deg[u], ++deg[v + n];
    	}
    	int ans = 0;
    	rep ( i, 1, n + m ) ans += !!( deg[i] % c );
    	printf( "%d
    ", ans );
    	return 0;
    }
    
    
  • 相关阅读:
    LeetCode:位运算实现加法
    Java基础教程:多线程基础——内存模型
    Python:笔记(3)——面向对象编程
    Java基础教程:反射基础
    MYSQL:基础——3N范式的表结构设计
    GIT学习笔记(1):创建版本库
    你为什么应该经常访问招聘网站?招聘网站至少有4个方面的价值!
    你为什么应该经常访问招聘网站?招聘网站至少有4个方面的价值!
    MySql update inner join!MySql跨表更新 多表update sql语句?如何将select出来的部分数据update到另一个表里面?
    MySql update inner join!MySql跨表更新 多表update sql语句?如何将select出来的部分数据update到另一个表里面?
  • 原文地址:https://www.cnblogs.com/rainybunny/p/15376481.html
Copyright © 2011-2022 走看看