题面描述
[题意翻译]
有一个n个顶点m条边的无向图,在一对顶点中最多有一条边。
设v1,v2是两个不相交的非空子集,当满足以下条件时f(v1,v2)为真
1、v1中的点之间不存在边
2、v2中的点之间不存在边
3、对于在v1,v2中的每一对顶点,x在v1中,y在v2中,x,y之间有边
所有点集不为空,且不相交,是否有v1,v2,v3使得f(v1,v2)、f(v2,v3)、f(v3,v1)均为真
如果有输出每个点所在的点集(1,2,3),否则输出-1
输入格式
第一行输入n,m。
n
≤
1
e
5
,
m
≤
3
e
5
n \le 1e5 , m\le3e5
n≤1e5,m≤3e5
接下来m行,每行两个数a,b。表示a,b间有一条无向边。
输出格式
如果有输出每个点所在的点集(1,2,3),否则输出-1
思路
这道题分步做,
首先考虑没有直接相连的点一定是一个集合。那么我们取三个没用过的点,把和这三个点直接相连的点分到对应的组。
然后我们check三个组是否满足条件即可。
注意我们的分组方式,同一组中,两个点之间可能有边相连。这种情况也是-1。
/*
* @Author: chenkexing
* @Date: 2019-10-29 17:38:47
* @Last Modified by: chenkexing
* @Last Modified time: 2019-10-29 18:20:01
*/
// #pragma GCC optimize(2)
// #pragma GCC optimize(3)
// #pragma GCC optimize(4)
#include <algorithm>
#include <iterator>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <iomanip>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <stack>
#include <cmath>
#include <queue>
#include <list>
#include <map>
#include <set>
#include <cassert>
//#include <unordered_set>
//#include <unordered_map>
// #include<bits/extc++.h>
// using namespace __gnu_pbds;
using namespace std;
#define pb push_back
#define fi first
#define se second
#define debug(x) cerr<<#x << " := " << x << endl;
#define bug cerr<<"-----------------------"<<endl;
#define FOR(a, b, c) for(int a = b; a <= c; ++ a)
typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int inf = 0x3f3f3f3f;
const ll inff = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9+7;
template<typename T>
inline T read(T&x){
x=0;int f=0;char ch=getchar();
while (ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar();
while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x=f?-x:x;
}
/**********showtime************/
const int maxn = 1e5+9;
set<int>mp[maxn];
vector<int>zu[4];
int vis[maxn];
pii edge[maxn*3];
int cnt[maxn];
int n, m;
/*** 把不直接相连的点放到一组***/
int pushZu(int u, int id) {
vis[u] = id;
zu[id].pb(u);
queue<int>que;
for(int i=1; i<=n; i++) {
if(vis[i]) continue;
if(mp[u].find(i) == mp[u].end()) {
vis[i] = id;
zu[id].pb(i);
}
else que.push(i);
}
if(que.empty()){ return 0;}
return que.front();
}
/*** 检查每个s组中的点与t组中的点两两有边相连 ***/
bool check(int s, int t) {
for(int i=1; i<=n; i++) cnt[i] = 0;
for(int i=1; i<=m; i++) {
int u = edge[i].fi, v = edge[i].se;
if(vis[u] == s && vis[v] == t) {
cnt[u]++;
}
if(vis[u] == t && vis[v] == s) {
cnt[v]++;
}
}
for(int i=0; i<zu[s].size(); i++) {
if(cnt[zu[s][i]] != zu[t].size()) return false;
}
return true;
}
int main(){
scanf("%d%d", &n, &m);
for(int i=1; i<=m; i++) {
int u, v;
scanf("%d%d", &u, &v);
mp[u].insert(v);
mp[v].insert(u);
edge[i] = pii(u, v);
}
int flag = 1;
int nx = pushZu(1, 1);
if(nx <= 0) {flag = 0;}
else {
nx = pushZu(nx, 2);
if(nx <= 0) {flag = 0;}
else {
nx = pushZu(nx, 3);
if(nx != 0) {flag = 0;}
}
}
/***由于选点的方式, 每组中的两点之间可能存在边***/
ll tot = zu[1].size() * zu[2].size() + zu[2].size() * zu[3].size() + zu[1].size() * zu[3].size();
if(tot != m) flag = 0;
if(flag == 0) puts("-1");
else {
if(check(1, 2) && check(2, 3) && check(3, 1)) {
for(int i=1; i<=n; i++) printf("%d ", vis[i]);
puts("");
}
else puts("-1");
}
return 0;
}