一、题目
二、解法
首先三个黑点、三个白点是肯定能能组队的,我们考虑白点数模 3 3 3余 1 1 1的情况(黑点如此同理)
此时能够组队的方案有一白两黑,或者是 2 2 2个两白一黑,都去试一试就行了,大于 3 3 3的特殊配对(不是三个同色)肯定不用考虑,因为都能归类到上述情况中去。至于解决上述问题,贪心地找度数最小的白点 / / /黑点,再看看能不能有两个点和他们组队。
还有一个问题,就是第一个点染什么颜色会不会有影响?我们讨论连通块个数, 1 1 1个显然无影响, 2 2 2个不清楚,但是好枚举(都试试看,反正只有两种本质不同的情况), 3 3 3个及以上就需要说明。
可以通过连虚边来化为
3
3
3个联通块的情况,这样限制更多,但若任然合法则可以说明问题,来讨论大小为
1
1
1的连通块的个数(其他情况可以通过不同连通块组队化成这种情况):
嫖了jzm的证明…
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <queue>
using namespace std;
const int M = 100005;
const int inf = 0x3f3f3f3f;
int read()
{
int num=0,flag=1;char c;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
while(c>='0'&&c<='9')num=(num<<3)+(num<<1)+(c^48),c=getchar();
return num*flag;
}
int n,m,k,cnt,tot,w,b,shit[M];
int du[M],f[M],fa[M],use[M],col[M];
struct edge
{
int v,next;
edge(int V=0,int N=0) : v(V) , next(N) {}
}e[2*M];
int find(int x)
{
if(x==fa[x]) return x;
return fa[x]=find(fa[x]);
}
void uni(int u,int v)
{
int x=find(u),y=find(v);
if(x==y) return;
k--;fa[x]=y;
}
void fuck(int u,int c)
{
if(col[u]!=-1) return ;
col[u]=c;
if(c==0) w++;
else b++;
for(int i=f[u];i;i=e[i].next)
fuck(e[i].v,c^1);
}
void paint(int f)
{
w=b=0;
memset(col,-1,sizeof col);
for(int i=1;i<=n;i++)
if(i==fa[i])
fuck(i,f);
}
int work2(int fl)
{
int mx=inf,t=0;
for(int i=1;i<=n;i++)
if(du[i]<mx && col[i]==fl && !use[i])
{
t=i;
mx=du[i];
}
int x=2;
memset(shit,0,sizeof shit);
for(int i=f[t];i;i=e[i].next)
if(col[e[i].v]==fl^1)
shit[e[i].v]=1;
for(int i=1;i<=n;i++)
if(!shit[i] && col[i]==fl^1 && !use[i])
x--;
if(x>0) return 0;
cnt++;x=2;
use[t]=cnt;
for(int i=1;i<=n;i++)
if(!shit[i] && col[i]==fl^1 && !use[i])
{
use[i]=cnt;
x--;if(x==0) return 1;
}
return 1;
}
void print()
{
queue<int> q1,q2;
for(int i=1;i<=n;i++)
{
if(!use[i] && col[i]==0)
q1.push(i);
if(!use[i] && col[i]==1)
q2.push(i);
}
while(!q1.empty())
{
cnt++;
for(int i=0;i<3;i++)
{
int t=q1.front();q1.pop();
use[t]=cnt;
}
}
while(!q2.empty())
{
cnt++;
for(int i=0;i<3;i++)
{
int t=q2.front();q2.pop();
use[t]=cnt;
}
}
puts("YES");
for(int i=1;i<=n;i++)
printf("%d ",use[i]);
exit(0);
}
void work()
{
cnt=0;
if(w%3==1)
{
//一白两黑
if(work2(0))
print();
//两黑四白
if(w>=4 && work2(1) && work2(1))
print();
}
else
{
if(work2(1))
print();
if(b>=4 && work2(0) && work2(0))
print();
}
}
signed main()
{
n=k=read();m=read();
for(int i=1;i<=n;i++)
fa[i]=i;
for(int i=1;i<=m;i++)
{
int u=read(),v=read();
e[++tot]=edge(v,f[u]),f[u]=tot;
e[++tot]=edge(u,f[v]),f[v]=tot;
du[u]++;du[v]++;
uni(u,v);
}
paint(0);
memset(use,0,sizeof use);
if(w%3) work();
else print();
if(k==2)
{
int x=0;
w=b=0;
memset(col,-1,sizeof col);
for(int i=1;i<=n;i++)
if(i==fa[i])
{
fuck(i,x);
x^=1;
}
memset(use,0,sizeof use);
if(w%3) work();
else print();
}
puts("NO");
}