其 实 很 好 写 其实很好写

首 先 因 为 要 分 三 组 , 那 我 们 就 先 分 三 组 , 保 证 组 内 点 都 是 互 相 不 连 通 的 首先因为要分三组,那我们就先分三组,保证组内点都是互相不连通的 ,,

所 以 先 枚 举 1 个 点 , 把 这 个 点 所 有 不 可 达 的 点 标 记 并 记 作 集 合 1 所以先枚举1个点,把这个点所有不可达的点标记并记作集合1 1,1

再 用 相 同 方 式 构 造 集 合 2 , 3 再用相同方式构造集合2,3 23

此 时 如 果 三 个 集 合 没 有 把 所 有 点 包 含 进 来 说 明 不 可 行 此时如果三个集合没有把所有点包含进来说明不可行

假 如 有 答 案 , 我 们 这 样 构 造 一 定 是 对 的 假如有答案,我们这样构造一定是对的 ,

接下来是重点,如何验证每个点集可行?

首 先 如 果 三 个 点 集 分 别 由 q , w , e 个 点 首先如果三个点集分别由q,w,e个点 q,w,e

那 么 q ∗ w + q ∗ e + w ∗ e = = m 那么q*w+q*e+w*e==m qw+qe+we==m

但 是 光 是 这 一 条 还 不 够 但是光是这一条还不够

我 们 去 d f s , 集 合 为 1 的 点 只 能 去 集 合 为 2 , 3 的 点 , 根 据 这 个 判 断 集 合 是 否 可 行 我们去dfs,集合为1的点只能去集合为2,3的点,根据这个判断集合是否可行 dfs,12,3,

虽 然 上 面 的 步 骤 仍 然 会 有 漏 网 之 鱼 , 但 是 这 种 数 据 还 是 比 较 难 构 造 的 虽然上面的步骤仍然会有漏网之鱼,但是这种数据还是比较难构造的 ,

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
vector<int>vec[maxn];
int n,m,flag=1,vis[maxn],a[maxn],duo;
set<int>s[maxn];
void dfs(int u)
{
	duo++;vis[u]=1;
	if(flag==0)	return;
	for(int i=0;i<vec[u].size();i++)
	{
		int v=vec[u][i];
		if(a[v]==a[u])	flag=0;
		if(vis[v])	continue;
		if(flag==0)	return ;
		if(a[v]!=a[u])	dfs(v);
	}
}
void over(){
	cout<<"-1";
	exit(0);
}
int main()
{
	cin >> n >> m;
	for(int i=1,l,r;i<=m;i++)
	{
		scanf("%d%d",&l,&r);
		s[l].insert(r);
		s[r].insert(l);
		vec[l].push_back(r);
		vec[r].push_back(l);
	}
	int k=0;
	for(int i=1;i<=n;i++)
	{
		if(vis[i])	continue;
		k++;
		if(k>3)	over();
		vis[i]=1,a[i]=k;
		for(int j=1;j<=n;j++)
		{
			if(i==j)	continue;
			if( s[i].count(j) )	continue;
			a[j]=k; vis[j]=1;
		}
	}
	if(k!=3)	over();
	memset(vis,0,sizeof(vis));
	
	int q=0,w=0,e=0;
	for(int i=1;i<=n;i++)
	if(a[i]==1)	q++;
	else if(a[i]==2)	w++;
	else	e++;
	
	for(int i=n;i>=1;i--)
		if(vis[i]==0)	dfs(i);
		
	if(flag==0||duo!=n||q*w+q*e+w*e!=m)	over();
	else
	{
		for(int i=1;i<=n;i++)
			cout<<a[i]<<" ";
	}	
}