题意:
n点m边无向图,无自环,无重边
给定的图可以断开连接
下面我们有一个定义:让v1和v2为两个不连通的顶点非空子集
函数f(v1, v2)为真当且仅当下面所有情况否满足:
1. 顶点集v1中的两点无边连接
2.顶点集v2中的两点无边连接
3.对任意在v1中的点和v2中的点,两点间有一条边
创造三个顶点集v1,v2,v3满足如下条件
1.所有顶点集不空
2.每个顶点只能在一个顶点集中
3.f(v1, v2) f(v2, v3) f(v3, v4)都为真
有可能创造这个顶点集吗,如果可能,请打印每个顶点的匹配顶点集
简而言之:就是创建一个三分图。
思路:
存边的时候,注意下可能输入的左点大于右点,可以存双边,或者存单边使左点小于右点
存边同时记录下度数。
然后进行集合分配,初始化所有点都是集合1的,从点1开始遍历其邻点,其邻点必须非集合1,先置为集合2
然后再从集合2开始遍历邻点,当某点必须非集合1和集合2,那么就置为集合3,如果三者都非,那么就可以直接退出
当集合分配正常完成后,我们就可以判断下集合之间的边数是否等于总边数。
此外还要判断三个集合是否都非空。
注意最后输出的时候,是按照点的顺序输出点的所在集合(没看清被坑了三四发WA
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 100, M = 3e5 + 100;
int n, m;
int h[N], e[M], ne[M], idx;
int color[N];
int val[5];
void add(int a, int b){
e[idx] = b;
ne[idx] = h[a];
h[a] = idx++;
}
int main()
{
scanf("%d%d", &n, &m);
memset(h, -1, sizeof h);
for(int i = 1; i <= n; i++) color[i] = 1;
for(int i = 0; i < m; i++){
int a, b;
scanf("%d%d", &a, &b);
/*add(a, b);
add(b, a);*/
if(a < b) add(a, b);
else add(b, a);
}
for(int i = 1; i <= n; i++)
color[i] = 1;
val[1] = n;
int flag = 0;
for(int g = 1; g <= n; g++){
for(int i = h[g]; i != -1; i = ne[i]){
int j = e[i];
if(color[j] == color[g]){
if(color[j] == 1) {
color[j] = 2;
val[1]--;
val[2]++;
}
else if(color[j] == 2) {
color[j] = 3;
val[2]--;
val[3]++;
}
else if(color[j] == 3){
flag = 1;
break;
}
}
}
if(flag) break;
}
if(val[1] * val[2] + val[1] * val[3] + val[2] * val[3] != m) flag = 1;
if(flag || val[1] == 0 || val[2] == 0 || val[3] == 0 || m == 0) puts("-1");
else {
for(int i = 1; i <= n; i++) printf("%d%s", color[i], (i == n) ? "\n" : " ");
}
return 0;
}