题意
二维平面上有 \(n\) 个点 \((x_i,y_i)\),你需要给每个点染色红色或蓝色使得每一行、每一列上红蓝点数差小于等于 1。
\(n,x_i,y_i\le 2\times10^5\)。
分析
方法一:上下界网络流
对所有行和列建点,\(x_i\rightarrow y_i\) 连边,流量 \([0,1]\),有流量表示染红。源点向行点连边,流量 \([\lfloor\frac{p_i}{2}\rfloor,\lceil\frac{p_i}{2}\rceil]\),\(p_i\) 是 \(i\) 行点数,表示染的红点数量必须要在这段区间内与蓝点数量的差才合法。列点向汇点连边,流量同理。
方法二:欧拉回路
可能是一个经典套路。套路性的建行点列点,\(x_i,y_i\) 间连一条无向边。但是这个建模不是很能契合欧拉回路的特征(可能会有奇度点)。不难发现若一行有奇数个点那么两两配对后剩下的点可以随便选,新建一个虚点将所有奇点连向它即可。现在所有点度数为偶,任选起点跑欧拉回路即可,颜色根据边的经过方向定。
方法三:二分图染色
我认为非常优美的思路,我想不到。
将一行内的点两两配对,剩下一个点不管。列同理。
可以证明该图为二分图。
感性证明:根据建模,一个点只会跟至多一个与它同横坐标的点和至多一个与它同纵坐标的点连边。假设有点 \((x,y)-(x,z),y\neq z\),由于 \((x,z)\) 已经跟一个横坐标与其相同的点连过边了,那么另一条出边必然和其纵坐标相同,以此类推,当走到与 \((x,y)\) 同侧的点时,其与其入点的纵坐标相同,故若形成奇环,那么这个点一定要和 \((x,y)\) 连边。而 \((x,y)\) 的横坐标边已经跟 \((x,z)\) 相连了,这与一行内点两两匹配的建模方式相悖,因此得证。
给出方法三代码,非常好写:
int n;
vector<int>G[maxn];
int lstx[maxn],lsty[maxn];
int col[maxn];
void dfs(int x,int c){
col[x]=c;
for(int u:G[x])if(!col[u])dfs(u,-c);
}
inline void solve_the_problem(){
n=rd();
rep(i,1,n){
int x=rd(),y=rd();
if(!lstx[x])lstx[x]=i;
else G[lstx[x]].emplace_back(i),G[i].emplace_back(lstx[x]),lstx[x]=0;
if(!lsty[y])lsty[y]=i;
else G[lsty[y]].emplace_back(i),G[i].emplace_back(lsty[y]),lsty[y]=0;
}
rep(i,1,n)if(!col[i])dfs(i,1);
rep(i,1,n)pc(col[i]==1?'r':'b');
}
标签:连边,Mike,int,Fish,CF547D,建模,lsty,lstx,col
From: https://www.cnblogs.com/dcytrl/p/18450669