这个 D 还是十分友好的~
你发现这 $3$ 个集合形成了一个环的关系,所以随意调换顺序是无所谓的.
然后随便让 $1$ 个点成为第 $2$ 集合,那么不与这个点连边的一定也属于第二集合.
然后再随便找一个与所选点有连边的点,将这个设为第 $3$ 集合中的点,然后与这个点有连边且不为第二集合的就是第一集合的.
构造出了 $3$ 个集合后再判断一下是否不合法即可.
几个判断方式:
1. 一个集合中不能有连边
2. 任意一个集合中所有点出边的数量应该相同.
3. 任何一个点集都不能为空.
#include <bits/stdc++.h>
#define N 100004
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
vector<int>G[N];
int vised[N],ty[N],cnt[N];
int main()
{
// setIO("input");
int n,m,i,j,flag=0;
scanf("%d%d",&n,&m);
for(i=1;i<=m;++i)
{
int a,b;
scanf("%d%d",&a,&b);
G[a].push_back(b);
G[b].push_back(a);
}
ty[1]=2;
cnt[2]=1;
for(i=0;i<G[1].size();++i)
{
int v=G[1][i];
vised[v]=1;
}
// 对2染色.
for(i=2;i<=n;++i) if(!vised[i]) ty[i]=2, ++cnt[2];
// 判断 2 有没有不合法的.
/*
for(i=2;i<=n;++i)
{
if(ty[i]==2)
{
for(j=0;j<G[i].size();++j)
{
int v=G[i][j];
if(ty[v]==2) flag=1;
}
}
}
*/
// 对 3 染色.
for(i=1;i<=n;++i)
{
if(vised[i])
{
for(j=0;j<G[i].size();++j)
{
int v=G[i][j];
if(!ty[v])
{
ty[v]=1;
++cnt[1];
}
}
ty[i]=3;
++cnt[3];
break;
}
}
for(i=1;i<=n;++i) if(!ty[i]) ty[i]=3, ++cnt[3];
for(i=1;i<=n;++i)
{
if(ty[i]==1)
{
for(j=0;j<G[i].size();++j)
{
int v=G[i][j];
if(ty[v]==1) flag=1;
}
if(G[i].size()!=cnt[2]+cnt[3]) flag=1;
}
if(ty[i]==2)
{
for(j=0;j<G[i].size();++j)
{
int v=G[i][j];
if(ty[v]==2) flag=1;
}
if(G[i].size()!=cnt[1]+cnt[3]) flag=1;
}
if(ty[i]==3)
{
for(j=0;j<G[i].size();++j)
{
int v=G[i][j];
if(ty[v]==3) flag=1;
}
if(G[i].size()!=cnt[1]+cnt[2]) flag=1;
}
}
for(i=1;i<=n;++i) if(!ty[i]) flag=1;
if(!cnt[1]||!cnt[2]||!cnt[3]) flag=1;
if(flag) printf("-1\n");
else
{
for(i=1;i<=n;++i) printf("%d ",ty[i]);
}
return 0;
}