题目大意
给定一个二分图,请你给每条边一个颜色(0,1,2)
一个点的点权定义为其所有与之相连的边颜色和模3
任意一条边连接的两端点点权必须不同
请构造一种染色方案
结论
对每一个联通块进行分析。
首先说出我们的构造目标:左边点点权均为0,右边点点权均不为0,这样一定符合要求
具体构造方案是将右边的点分为两两一组,以其中一个为起点,另一个为终点,然后跑一条可行路径,因为是联通的,所以该路径一定存在。对于路径中经过的边,按1、2、1、2的去加,也就是路径中第一条经过的边颜色+1,第二条+2,第三条+1,第四条+2,以此类推。
我们发现,这样做,起点点权+1,终点点权+2,其余所有点点权不变!
但是,因为要两两一组,如果右边点的个数是奇数怎么办?
我们可以找到右边一个点权为1的点,以它为起点,以这个剩余的点为终点,再做一次。不过,我们应该想到,如果右边只有1个点,那一对都凑不成了!
但是如果左边有超过1个点,即使右边只有1个点,我们可以左右交换!
而显然, 无解的情况是左右都只有1个点。
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=3000+10,maxm=10000+10;
int h[maxn],s[maxn],x[maxn],y[maxn],go[maxm*2],next[maxm*2],co[maxm];
bool bz[maxn],pd[maxn];
int i,j,k,l,t,n,n1,n2,m,tot,xx,yy;
void add(int x,int y){
go[++tot]=y;
next[tot]=h[x];
h[x]=tot;
}
void dfs(int i,int c){
bz[i]=1;
if (!c) x[++xx]=i;else y[++yy]=i;
int t=h[i];
while (t){
if (!bz[go[t]]) dfs(go[t],1-c);
t=next[t];
}
}
bool dg(int x,int y,int c){
pd[x]=1;
if (x==y) return 1;
int t=h[x];
while (t){
if (!pd[go[t]]&&dg(go[t],y,1-c)){
(co[(t+1)/2]+=c+1)%=3;
return 1;
}
t=next[t];
}
}
void work(){
int i;
if (yy==1){
swap(x[1],y[1]);
fo(i,2,xx) y[i]=x[i];
swap(xx,yy);
}
fo(i,1,yy/2){
j=y[i*2-1];k=y[i*2];
fo(l,1,xx) pd[x[l]]=0;
fo(l,1,yy) pd[y[l]]=0;
dg(j,k,0);
s[j]=1;s[k]=2;
}
if (yy%2==1){
j=y[1];k=y[yy];
fo(l,1,xx) pd[x[l]]=0;
fo(l,1,yy) pd[y[l]]=0;
dg(j,k,0);
}
}
int main(){
scanf("%d%d%d",&n1,&n2,&m);
fo(i,1,m){
scanf("%d%d",&j,&k);
add(j,k+n1);add(k+n1,j);
}
fo(i,1,n1)
if (!bz[i]){
xx=yy=0;
dfs(i,0);
work();
}
printf("Yes\n");
fo(i,1,m) printf("%d ",co[i]);
}
808

被折叠的 条评论
为什么被折叠?



