这个 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 "); else { for(i=1;i<=n;++i) printf("%d ",ty[i]); } return 0; }