好久没这么深入地分析一道图论题了,感觉酣畅淋漓,虽然考场上花的时间比较久,但是好在分析得十分透彻,直接一Y了
考虑如果尽量把一种颜色分在同一边,那么肯定是合法的,如果说两边点数模2都余0,那就皆大欢喜了;唯一特殊的情况是一边多一个点,一边多2个点,由于所有颜色都是等价的,因此只需一边找一个点,另一边找两个与他不相邻的两个点即可满足要求,这个根据度数可以轻松判出;如果不存在这种情况的话,假设x部是多一个点,y部是多两个点,此时x部的点都肯定顶多只能在y中找到一个与它不相邻的点,这样子的话,原图就化为了一个由只有一层的树构成的森林,而且父亲在y部,儿子在x部,如果有两棵以上的树点数大于2,那么一开始剩的一种颜色就可以把要放在y部的一个点换到x部来,那个x部被挤出来的一种颜色有可以放到另一棵树中的y部去;如果这种情况也不满足的话,那么这个图就更加特殊了,顶多存在一棵超过两个点的树以及一系列只有一条边的两对点构成,显然剩下的那种颜色即便填进来,挤出去的颜色也没地方放,那么就是无解。时间复杂度是严格o(n+m)的。
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <algorithm>
const int oo=1073741819;
using namespace std;
int n,m,ss,u[2][200000],d[200000],v[200000],k;
int tail[2000000],next[2000000],sora[2000000];
int s[2],du[200000],ans[200000],st[200000];
void getout0()
{
printf("YES\n");
for (int i=1;i<=s[0];i+=3,k--)
for (int j=i;j<=i+2;j++) ans[u[0][j]]=k;
for (int i=1;i<=s[1];i+=3,k--)
for (int j=i;j<=i+2;j++) ans[u[1][j]]=k;
printf("%d",ans[1]);
for (int i=2;i<=n;i++) printf(" %d",ans[i]);
printf("\n");
}
void getout1(int e,int x)
{
printf("YES\n");
memset(v,0,sizeof(v));
for (int i=x,ne;next[i];) {
i=next[i],ne=sora[i];
v[ne]=1;
}
ans[x]=k;
for (int i=1,cnt=1;i<=s[e^1] && cnt<=2;i++) {
int ne=u[e^1][i];
if (!v[ne]) ans[ne]=k,cnt++;
}
k--;
for (int i=1,cnt=1;i<=s[0];i++) {
int ne=u[0][i];
if (ans[ne]) continue;
ans[ne]=k;
cnt++;
if (cnt>3) k--,cnt=1;
}
for (int i=1,cnt=1;i<=s[1];i++) {
int ne=u[1][i];
if (ans[ne]) continue;
ans[ne]=k;
cnt++;
if (cnt>3) k--,cnt=1;
}
printf("%d",ans[1]);
for (int i=2;i<=n;i++) printf(" %d",ans[i]);
printf("\n");
}
void getout2(int e,int x,int y)
{
printf("YES\n");
memset(v,0,sizeof(v));
for (int i=x,ne;next[i];) {
i=next[i],ne=sora[i];
v[ne]=1;
}
ans[x]=k;
for (int i=1,cnt=1;i<=s[e^1] && cnt<=2;i++) {
int ne=u[e^1][i];
if (!v[ne]) ans[ne]=k,cnt++;
}
k--;
memset(v,0,sizeof(v));
x=y;
for (int i=x,ne;next[i];) {
i=next[i],ne=sora[i];
v[ne]=1;
}
ans[x]=k;
for (int i=1,cnt=1;i<=s[e^1] && cnt<=2;i++) {
int ne=u[e^1][i];
if (!v[ne] && !ans[ne]) ans[ne]=k,cnt++;
}
k--;
for (int i=1,cnt=1;i<=s[0];i++) {
int ne=u[0][i];
if (ans[ne]) continue;
ans[ne]=k;
cnt++;
if (cnt>3) k--,cnt=1;
}
for (int i=1,cnt=1;i<=s[1];i++) {
int ne=u[1][i];
if (ans[ne]) continue;
ans[ne]=k;
cnt++;
if (cnt>3) k--,cnt=1;
}
printf("%d",ans[1]);
for (int i=2;i<=n;i++) printf(" %d",ans[i]);
printf("\n");
}
void origin()
{
ss=n;
for (int i=1;i<=n;i++) tail[i]=i;
}
void link(int x,int y)
{
du[x]++,du[y]++;
++ss,next[tail[x]]=ss,tail[x]=ss,sora[ss]=y;
++ss,next[tail[y]]=ss,tail[y]=ss,sora[ss]=x;
}
void bfs(int s1)
{
int h,r,ne,na;
h=r=0;
st[r=1]=s1,d[s1]=0;
for (;h<r;) {
ne=st[++h];
for (int i=ne;next[i];) {
i=next[i],na=sora[i];
if (d[na]>oo) {
d[na]=d[ne]^1;
st[++r]=na;
}
}
}
for (int i=1;i<=r;i++) {
ne=st[i];
int e=(d[ne]&1);
u[e][++s[e]]=ne;
}
}
int main()
{
scanf("%d%d",&n,&m);
origin();
for (int i=1;i<=m;i++) {
int x,y;
scanf("%d%d\n",&x,&y);
link(x,y);
}
memset(d,127,sizeof(d));
s[0]=s[1]=0;
for (int i=1;i<=n;i++)
if (d[i]>oo) bfs(i);
k=n/3;
if ((s[0]%3==0) && (s[1]%3==0)) {
getout0();
return 0;
}
int e;
if ((s[0]%3==1)) e=0;
else e=1;
// memset(v,0,sizeof(v));
int t=0;
for (int i=1;i<=s[e];i++) {
int ne=u[e][i];
if (s[e^1]-du[ne]>=2) {
t=ne;
break;
}
}
if (t) {
getout1(e,t);
return 0;
}
int p=0;
e^=1;
for (int i=1;i<=s[e];i++) {
int ne=u[e][i];
if (s[e^1]-du[ne]>=2) {
if (!t) t=ne;
else p=ne;
}
}
if ((t) && (p)) {
getout2(e,t,p);
return 0;
}
printf("NO\n");
return 0;
}