先完成 课前零食:两支队伍与奇怪的圈,再把“奇环冲突”带进构造题。
学完后,你应能用奇环刻画二分图,处理非连通分量的两种翻转选择,并把“每点只能做源或汇”“三标签相邻差 1”等构造条件还原成二分染色。
前置:BFS/DFS、连通分量、0/1 背包。
从任一点染 0,沿边交替染色。遇到同色边时,DFS/BFS 树上两条到根路径与该边形成奇环;反之奇环无法交替回到起点原色。因此“可二染”和“无奇环”充要。
一个连通分量的两侧集合记为 $A_i,B_i$。所有合法二染只能选“$A_i$ 为颜色 0”或整体交换。若题目还规定某颜色恰有 $K$ 个点,就转成从每个分量选择 $|A_i|$ 或 $|B_i|$ 的分组背包,并保存决策恢复方案。
连通简单无向图有 $n,m\le2\times10^5$。给所有边定向,使有向图中不存在长度至少 2 的路径;若可行,按输入边输出 0/1 方向串。
不存在长度 2 路径等价于没有点同时作为某条边终点和另一条边起点,所以每点必须纯入或纯出,邻点类型相反,原图必须二分。若二分,所有边从一侧指向另一侧,任一有向路径走一步就到纯汇,无法继续,构造成立。
时间 $O(n+m)$,输出位由输入方向与颜色比较决定。
two-color the graph
if an edge has equal-colored endpoints: output NO
otherwise orient every edge from color 0 to color 1
translate each orientation back to a 0/1 character in input order
完整 GNU C++17 参考实现见附件:CodeForces-1144F.cpp
若只要求无有向环,可以按任意顶点序给边从小到大定向,并不要求二分;“禁止长度 2”远强于“禁止环”。
简单无向图有 $n\le5000,m\le10^5$,需恰用 $n_1,n_2,n_3$ 个标签 1、2、3,并使每条边两端标签差恰为 1。输出任一方案或 NO。
任意边必须一端为 2,另一端为 1/3,所以图必须二分,且每个连通分量的某一整侧为 2。背包选择各分量哪侧,使总大小 $n_2$。选定后,所有非 2 点只与 2 相邻,它们之间无边,故任取 $n_1$ 个标 1 不会破坏条件。
反之任何合法标号诱导上述二分与分量选择,所以算法充要。染色 $O(n+m)$,背包 $O(n^2)$,适合 $n=5000$。
two-color every connected component and store its two sides
group-knapsack: from each component choose one side so total chosen size is n2
recover choices; label chosen side 2
among all remaining vertices label any n1 as 1 and the rest as 3
完整 GNU C++17 参考实现见附件:CodeForces-1354E.cpp
choice[i][sum] 保存到达状态时第 $i$ 个分量选哪侧;同一状态被覆盖无妨,只需恢复任一路径。need3 由总数自动满足,但读入保留以对应题意。
$n\le10^5$ 对情侣坐在环形排列的 $2n$ 张椅子上,每椅恰一人。给每人两种食物,要求情侣不同,且任意连续三人不能全相同。输出方案。
建立 $2n$ 个椅子点,加入情侣边与固定配对边 $(1,2),(3,4),\ldots$。每点各属于一条两类边,所以沿环行走两类边交替,所有环长度为偶数,必可二染。二染保证情侣不同,也保证每个固定椅对不同;任意三个连续椅子中包含一个完整固定对,因此不会三人同色。
复杂度 $O(n)$。情侣恰坐固定对时会出现两条平行边,但不影响二染。
make one vertex for each chair
add an inequality edge for every romantic pair
add inequality edges (1,2), (3,4), ...
two-color every resulting even-cycle component
output the two colors at each romantic pair's chair positions
完整 GNU C++17 参考实现见附件:CodeForces-741C.cpp
技巧不是“任意把相邻椅子配对”,而是选一组不交叠相邻对,使每个长度 3 窗口至少覆盖一对。若椅子数为奇数,这种完美配对不存在,构造需重新设计。
给定 $N,D_1,D_2$,其中 $1\le N\le300$,$1\le D_1,D_2\le2\times10^5$。从所有满足 $0\le x,y<2N$ 的格点中选出 $N^2$ 个,使任意两点的距离都不等于 $\sqrt{D_1}$ 或 $\sqrt{D_2}$。
这题的难点不是搜索点集,而是证明每一种平方距离都能把整张格点图切成两侧。
定义 color(x,y,D):只要 $4\mid D$,就令 $D\leftarrow D/4$ 且 $x\leftarrow\lfloor x/2\rfloor,y\leftarrow\lfloor y/2\rfloor$。终止后:
证明它是距离图的合法二染。设两格点差为 $(u,v)$ 且 $u^2+v^2=D$。当 $4\mid D$ 时,平方模 4 只能是 0 或 1,因此 $u,v$ 必须同为偶数;约去 2 后仍是同一形式。约分终止后,若 $D$ 奇,则 $u,v$ 一奇一偶,$(x+y)$ 奇偶必翻转;若 $D\equiv2\pmod4$,则 $u,v$ 都奇,$x$ 奇偶必翻转。因此每条距离平方为 $D$ 的边两端异色。
对 $D_1,D_2$ 分别算颜色,把点放入编号 2*c1+c2 的桶。同桶两点在两种染色下都同色,故不可能相距 $\sqrt{D_1}$ 或 $\sqrt{D_2}$。总点数为 $(2N)^2=4N^2$,至少一个桶有 $N^2$ 个点,取其中任意 $N^2$ 个即可。这同时证明构造不漏解目标,也说明无需尝试不同起点或回溯。
枚举格点的时间为 $O(N^2\log\max(D_1,D_2))$,空间为 $O(N^2)$;递归层数只等于因子 4 的个数。
function color(x, y, D):
while D % 4 == 0:
D = D / 4
x = floor(x / 2)
y = floor(y / 2)
if D is odd:
return (x + y) % 2
return x % 2
make four empty buckets
for x in 0 .. 2*N-1:
for y in 0 .. 2*N-1:
key = 2*color(x,y,D1) + color(x,y,D2)
append (x,y) to bucket[key]
output any N*N points from a bucket whose size is at least N*N
完整 GNU C++17 参考实现:AtCoder-agc025_d.cpp
2N 正好与两个约束匹配。第一题应独立完成;第二题先只求是否能选出 $n_2$,再加恢复;第三题不看代码手画 3 对情侣的辅助图。复盘时把每题的“二分两侧分别代表什么”写成一句语义,而不是只写颜色 0/1。