CF600F
Solution
算是一个经典结论了吧。
把一个二分图
而这个值能取到,使用构造法证明,顺带把这道题过了。
令
考虑按顺序依次加边。假设我们目前需要确定颜色的边为
如果
否则,假设
注意,这时候因为
u_2 连上的边的数量小于v ,所以一定能找到这样一个d 。
这样会引起一连串连锁反应。不过没关系,我们在图上不断走红黄交错的边。很容易注意到,我们永远不会得到环,因为根据设定,
那我们把这条极长的,红黄交错的路径全部翻转颜色(也就是红变黄,黄变红)即可。是不是很像找增广路?不过不完全一样就是了。
复杂度
脑筋急转弯:如果是把二分图的点染色,让每条边连的两个点颜色不同怎么办?答案是
代码(非递归找环版):
#include<bits/stdc++.h>
#define ffor(i,a,b) for(int i=(a);i<=(b);i++)
#define roff(i,a,b) for(int i=(a);i>=(b);i--)
using namespace std;
const int MAXN=1000+10,MAXM=1e5+10;
int n1,n2,m,lst,degl[MAXN],degr[MAXN],x[MAXM],y[MAXM],res[MAXM],id[MAXN][MAXN],tl[MAXN][MAXN],tr[MAXN][MAXN];
int main() {
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>n1>>n2>>m;
ffor(i,1,m) cin>>x[i]>>y[i],id[x[i]][y[i]]=i,degl[x[i]]++,degr[y[i]]++;
lst=max(*max_element(degl+1,degl+n1+1),*max_element(degr+1,degr+n2+1));
ffor(i,1,m) {
int u1=x[i],u2=y[i],flg=0;
ffor(j,1,lst) if(tl[u1][j]+tr[u2][j]==0) flg=j;
if(flg) tl[u1][flg]=u2,tr[u2][flg]=u1;
else {
int flg1=0,flg2=0;
ffor(j,1,lst) if(tl[u1][j]==0) flg1=j;
ffor(j,1,lst) if(tr[u2][j]==0) flg2=j;
vector<int> cl,cr;
int pos=u2;
while(pos) {
cr.push_back(pos);
if(tr[pos][flg1]) {
cl.push_back(tr[pos][flg1]);
pos=tl[tr[pos][flg1]][flg2];
}
else break ;
}
for(auto id:cl) swap(tl[id][flg1],tl[id][flg2]);
for(auto id:cr) swap(tr[id][flg1],tr[id][flg2]);
tl[u1][flg1]=u2,tr[u2][flg1]=u1;
}
}
ffor(i,1,n1) ffor(j,1,lst) res[id[i][tl[i][j]]]=j;
cout<<lst<<'\n';
ffor(i,1,m) cout<<res[i]<<' ';
return 0;
}